Codeforces Round 860(div.2)CD「贪心」

文章介绍了两道编程竞赛题目,第一题通过求解gcd和lcm来减少乘积的改变次数,第二题利用前缀和思想调整序列达到目标状态。核心是贪心策略和数学优化。

贪心yyds!

牛马B题卡我好久,不要在栈内开邻接表!少开邻接表!除了方便一无所有!

Problem - C - Codeforces

题意:

有n组数据,给你ai bi,你可以选ai的一个因子di,尽量使得连续的bi*di相等,求bi*di的值最少的改变次数是多少。

思路:

ai=t*di,aj=k*dj

ai*bi=t*di*bi,aj*bj=k*dj*bj

如果存在num=di*bi==dj*bj,很显然num是ai*bi和aj*bj的一个公因子,由于d是我们可以自己凑的,所以只需要判断对于bi来说这个公因子是否存在即可。

在两个数中,当(t,k)!=1的时候显然可以让d增加一倍的gcd(t,k)也必然成立,所以可以令num为ai*bi和aj*bj的一个gcd,然后去查这个gcd是不是b的倍数。

在很多数中,就需要让gcd是所有数的gcd,并且需要让gcd是所有b的lcm的倍数,出现不行的数就从当前数开始更新gcd和lcm的值,ans++。

#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define i64 __int64
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
int a[N], b[N];

void work() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i] >> b[i];
	}
	
	int d=a[1]*b[1], lcm=b[1], ans = 1, maxx = b[1];
	for (int i = 2; i <= n; ++i) {
		d = __gcd(d, a[i] * b[i]);
		lcm = b[i] * lcm / __gcd(b[i], lcm);
		if (d % lcm) {
			d = a[i] * b[i];
			lcm = b[i];maxx = b[i];ans++;
		}
	}
	cout << ans << '\n';
}

signed main() {
	io;
	int t;
	cin >> t;
	while (t--) {
		work();
	}
	return 0;
}

 Problem - D - Codeforces

思路:

正了加负,负了加正,保持前缀和一直向0靠,只要不是全0串就都可以做到。 

#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define i64 __int64
//#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
int a[N], ans[N];

void work() {
	int n;
	cin >> n;
	bool flag = 0;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		if (a[i] != 0)
			flag = 1;
	}
	if (!flag) {
		cout << "No\n";
		return;
	}

	sort(a + 1, a + 1 + n);
	int l = 1, r = n, tmp = 0;
	int maxx = 0;
	while (l <= r) {
		if (maxx <= 0) {
			ans[++tmp] = a[r--];
			maxx += ans[tmp];
		} else {
			ans[++tmp] = a[l++];
			maxx += ans[tmp];
		}
	}
	cout << "YES\n";
	for (int i = 1; i <= n; ++i) {
		cout << ans[i] << " ";
	}
	cout << '\n';
}

signed main() {
	io;
	int t;
	cin >> t;
	while (t--) {
		work();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值