Codeforces Round #665 (Div. 2) (A-D)

题目

A - Distance and Axis

选一点 B ,使得 ∣ O A − A B ∣ |OA-AB| OAAB为 K 时 A 需要挪动多少单位。那么当OA <= k 时,使AB=0,需要挪动k-OA。当OA>k 时 B 点必须在OA内,此时 OA 分解为a、b之和,那么当OA为奇数时 k = ∣ a − b ∣ k=|a-b| k=ab 为奇数,当OA为偶数时 k = ∣ a − b ∣ k=|a-b| k=ab 为偶数。所以根据 k 的奇偶性改变OA的奇偶性即可。

#include
using namespace std;
int main()
{
	int T; cin>>T;
	while(T--){
		int a,k;
		cin>>a>>k; 
		if(a<=k) cout<<k-a<<"\n";
		else {
			if((a%2==0&&k%2==0)||(a%2==1&&k%2==1)) cout<<"0\n";
			else cout<<"1\n";
		}
	}
	return 0;
}

B - Ternary Sequence

只有 (2,1) 的结果为2,(1,2)的结果为 -2 ,其余均为 0。所以组成尽量多的(2,1)后,使用 a 中的0、2消耗 b 中的 2,最后剩下的只能和 a 中的 1 匹配,减去即可。

#include
using namespace std;

int main()
{
	int T; cin>>T;
	while(T--){
		LL a,b,c,x,y,z; 
		cin>>a>>b>>c>>x>>y>>z;
		LL ans = min(c,y)*2;
		if(c>y) z -= (c-y);
		ans -= max(z-a,0)*2;
		cout<<ans<<"\n";
	}
	return 0;
}

C - Mere Array *

题意: 使用以下操作后,判断是否能使给定数组按照非递减排序。操作:设数组中的最小值为M,当 g c d ( a i , b j ) = M gcd(a_i,b_j)=M gcd(ai,bj)=M 时可以交换两数的位置。
思路: 那么让需要交换的两个数都通过最小的数中转交换,此时需要的限制是最弱的,若此时不能成功那么就不会成功了。

#include
using namespace std;
typedef long long LL;
const int N = 2e5+7;
int a[N],b[N];

int main()
{
	int T; cin>>T;
	while(T--){
		int n;
		cin>>n;
		for(int i=0;i<n;i++){
			cin>>a[i];
			b[i]=a[i];
		}
		sort(b,b+n);
		int flag=1;
		for(int i=0;i<n;i++){
			if(a[i]!=b[i]&&__gcd(a[i],b[0])!=b[0]) flag=0;
		}
		if(flag) cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
}

D - Maximum Distributed Tree*

在这里插入图片描述

题意: 给一颗树的 n-1 条边赋值,使得 ∑ i = 1 n − 1 ∑ j = i + 1 n f ( i , j ) \sum\limits_{i=1}^{n-1} \sum\limits_{j=i+1}^n f(i,j) i=1n1j=i+1nf(i,j) 最大,其中 f ( u , v ) f(u,v) f(u,v) 代表 u 到 v 的简单路径。
赋值的限制:1、每个权值大于0 。2、n-1 个边权的乘积等于k。3、边权中1的数量尽量少。
其中 k 以 p 个素数因子的形式给出。
思路: 需要求的是所有路径的和,所以我们直接计算每条边经过的次数,然后贪心地给经过次数较多的边以 p 中的较大的值,若 p < n-1,则补1,若 p > n-1,则删去最大的p - (n-2) 个数,用他们的乘积代替。

#include
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int N = 2e5+7;

int h[N],e[N*2],ne[N*2],idx;
LL si[N]; 

void add(int a,int b){
	e[idx] = b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int x,int f){
	si[x] = 1;
	for(int i=h[x];i!=-1;i=ne[i]){
		int j = e[i];
		if(j==f) continue;
		dfs(j,x);
		si[x] += si[j];	 // 每个子树的大小
	}
}

int main()
{
	int T; cin>>T;
	while(T--){
		LL n;
		cin>>n;
		memset(h,-1,sizeof h);
		idx=0;
		for(int i=1;i<n;i++){
			int x,y;
			cin>>x>>y;
			add(x,y),add(y,x);
		} 
		vector<LL> pp,ve;
		LL p,x;
		cin>>p;
		for(int i=0;i<p;i++) cin>>x,pp.push_back(x);
		for(int i=p;i<n-1;i++) pp.push_back(1);
		dfs(1,0); 
		for(int i=2;i<=n;i++) ve.push_back(si[i]*(n-si[i]));//每条边的两端的节点的个数的乘积既是经过次数
		sort(ve.begin(),ve.end());
		sort(pp.begin(),pp.end());
		while(pp.size()>n-1){    //删去多于n-1的边
			LL x = pp.back();pp.pop_back();
			LL y = pp.back();pp.pop_back();
			pp.push_back(x*y%mod);
		}
		sort(pp.begin(),pp.end());  //再次排序
		LL ans=0;
		for(int i=0;i<n-1;i++) ans = (ans + pp[i]*ve[i])%mod;
		cout<<ans<<"\n";
	}
	return 0;
}

你可能感兴趣的:(CF,贪心)