天天看點

Codeforces Round #665 (Div. 2) A-D 題解A. Distance and AxisB. Ternary SequenceC. Mere ArrayD. Maximum Distributed Tree

A. Distance and Axis

題目連結

題目原文

Codeforces Round #665 (Div. 2) A-D 題解A. Distance and AxisB. Ternary SequenceC. Mere ArrayD. Maximum Distributed Tree

題目大意

在 O X OX OX軸上,給出點 A A A的坐标 x = n x=n x=n,給出一個值 k k k,求問能不能在 O X OX OX軸上找一個點 B B B,使得你 ∣ O A − A B ∣ = k |OA-AB|=k ∣OA−AB∣=k。如果不能找到,你每次可以将 A A A點的坐标 + 1 +1 +1或 − 1 -1 −1,求至少移動點 A A A多少次,使得可以找到點 B B B (如果以開始就能找到,那麼輸出 0 0 0 )。

解題思路

由題意得 O A = n OA=n OA=n,設 B B B的坐标為 y y y,那麼 ∣ A B ∣ = ∣ n − y ∣ |AB|=|n-y| ∣AB∣=∣n−y∣,那麼 ∣ O A − A B ∣ = ∣ 2 n − y ∣ |OA-AB|=|2n-y| ∣OA−AB∣=∣2n−y∣,是以就是求是否存在 2 n − y 2n-y 2n−y等于 k k k。

解法

如果 n < k n<k n<k,那麼一定解出來 y y y是負數,是以一定要将點 A A A移動到 x = k x=k x=k處,答案為 n − k n-k n−k。

如果 n − k n-k n−k為奇數,那麼除以2之後為小數,是以應該 + 1 +1 +1或 − 1 -1 −1,答案為 1 1 1。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
int T,n,k,ans;
int main()
{
 	#ifdef lemon
	freopen("A.txt","r",stdin);
	#endif
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&k);
		ans=0;
		if(n<k) ans+=k-n,n=k;
		else if((n-k)&1) ans++;
		printf("%d\n",ans);
	}
	return 0;
}

           

B. Ternary Sequence

題目連結

題目原文

Codeforces Round #665 (Div. 2) A-D 題解A. Distance and AxisB. Ternary SequenceC. Mere ArrayD. Maximum Distributed Tree

題目大意

有兩個數組 a a a和 b b b,這兩個數組都隻會有3個值:0或1或2。現在告訴你這兩個數組中這三個值的數量。請你構造 a , b a,b a,b數組,并且由下面規則生成 c c c數組,并且使得 c c c數組每一項的和最大,求這個最大值。

規則:

c i = { a i b i if  a i > b i 0 if  a i = b i − a i b i if  a i < b i c_i = \begin{cases} a_i b_i &\text{if } a_i > b_i \\ 0 &\text{if } a_i = b_i \\ -a_i b_i &\text{if } a_i < b_i \end{cases} ci​=⎩⎪⎨⎪⎧​ai​bi​0−ai​bi​​if ai​>bi​if ai​=bi​if ai​<bi​​

解題思路

這種題看過去不是貪心就是dp。

解法

我們貪心地想,首先要使得 a i = 2 ,    b i = 1 a_i=2, \; b_i=1 ai​=2,bi​=1的數量盡可能地多,然後盡可能地使得其他都為0,最後實在不行再使得值為 a i = 1 ,    b i = 2 a_i=1, \; b_i=2 ai​=1,bi​=2。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
int T;
long long x1,yy1,z1,x2,y2,z2;
int main()
{
 	#ifdef lemon
	freopen("B.txt","r",stdin);
	#endif
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld%lld%lld",&x1,&yy1,&z1,&x2,&y2,&z2);
		long long t1=min(z1,y2),ans=0;
		z1-=t1;y2-=t1;
		ans+=2ll*t1;
		long long t2=min(z1,z2);
		z1-=t2;z2-=t2;
		long long t3=min(x1,z2);
		x1-=t3;z2-=t3;
		ans-=2ll*z2;
		printf("%lld\n",ans);
	}
	return 0;
}
           

C. Mere Array

題目連結

題目原文

Codeforces Round #665 (Div. 2) A-D 題解A. Distance and AxisB. Ternary SequenceC. Mere ArrayD. Maximum Distributed Tree

題目大意

給出長度為 n n n的數組,每個數都大于1。記數組中最小的數為minn,現在你可以将數組中任意兩個 g c d = m i n n gcd=minn gcd=minn的數進行交換。求有沒有可能使得整個數組變成不下降序列。

解題思路

顯然minn可以和所有數進行交換,那就将minn作為交換的中間值。

解法

将數組中是minn的倍數的數提出來,直接排序(因為他們都可以通過minn進行交換)。然後從小到大插入提出來的位置。最後check一下數組,如果這個數組滿足要求,那麼就ok。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
int a[maxn],b[maxn],c[maxn],T,n;
int main()
{
 	#ifdef lemon
	freopen("C.txt","r",stdin);
	#endif
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		int minn=0x7f7f7f7f;b[0]=0;
		for(int i=1;i<=n;i++) scanf("%d",&a[i]),minn=min(minn,a[i]);
		for(int i=1;i<=n;i++) if(a[i]%minn==0) b[++b[0]]=a[i];
		sort(b+1,b+b[0]+1);
		int p=1;
		for(int i=1;i<=n;i++)
		{
			if(a[i]%minn) c[i]=a[i];
			else c[i]=b[p++];
		}
		bool flag=true;
		for(int i=2;i<=n;i++) if(c[i]<c[i-1]) flag=false;
		if(flag) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
           

D. Maximum Distributed Tree

題目連結

題目原文

Codeforces Round #665 (Div. 2) A-D 題解A. Distance and AxisB. Ternary SequenceC. Mere ArrayD. Maximum Distributed Tree

題目大意

給出一棵樹,但沒有邊權。

給出一個數的因數形式(給出的數的乘積為k)。

現在你需要給每一條邊指派,使得所有每兩個點之間通過的路徑和最大,且邊權需要滿足以下要求:

  1. 每條邊的邊權必須大于0
  2. 所有邊的邊權之積為k
  3. 邊權為1的邊的數量盡可能地少

解題思路

顯然我們需要将通過最多的邊指派最大,通過次數最低的邊指派最小。于是我們想到貪心。

解法

用樹形dp求出每條邊的通過次數,對于一條邊i,它的通過次數等于它的子樹大小*(n-它的子樹大小)。然後再貪心求解。

注意m>n-1的情況!

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
const long long mod=1e9+7;
int T,n,head[maxn],k=0,size[maxn],tot,m;
struct node
{
	int to,next;
} edge[maxn<<1];
void add(int u,int v)
{
	edge[++k].to=v;
	edge[k].next=head[u];
	head[u]=k;
}
long long p[maxn],ans=0,b[maxn];
void dfs(int x,int fa)
{
	size[x]=1;
	for(int i=head[x];i;i=edge[i].next)
	{
		if(edge[i].to==fa) continue;
		dfs(edge[i].to,x);
		size[x]+=size[edge[i].to];
		b[++tot]=(long long)size[edge[i].to]*(long long)(n-size[edge[i].to]);
	}
}
int main()
{
 	#ifdef lemon
	freopen("D.txt","r",stdin);
	#endif
	scanf("%d",&T);
	while(T--)
	{
		memset(head,0,sizeof(head));k=0;tot=0;ans=0;
		scanf("%d",&n);
		for(int i=1,x,y;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			add(x,y);add(y,x);
		}
		scanf("%d",&m);
		for(int i=1;i<=m;i++) scanf("%lld",&p[i]);
		dfs(1,1);
		sort(b+1,b+tot+1);
		sort(p+1,p+m+1);
		p[0]=1ll;
//		for(int i=1;i<=tot;i++) printf("%d ",b[i]);printf("\n");
		while(m>tot)
		{
			p[m-1]=(p[m-1]*p[m])%mod;
			m--;
		}
		int pp=m;
		for(int i=tot;i;i--)
		{
			b[i]%=mod;
			ans=(ans+(b[i]*p[pp])%mod)%mod;
			pp--;
			if(pp<0) pp=0;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
           

繼續閱讀