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

A. Distance and Axis

题目链接

题目原文

Codeforces Round #665 (Div. 2) A-D 题解_第1张图片

题目大意

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 OAAB=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=ny,那么 ∣ O A − A B ∣ = ∣ 2 n − y ∣ |OA-AB|=|2n-y| OAAB=2ny,所以就是求是否存在 2 n − y 2n-y 2ny等于 k k k

解法

如果 n < k nn<k,那么一定解出来 y y y是负数,所以一定要将点 A A A移动到 x = k x=k x=k处,答案为 n − k n-k nk

如果 n − k n-k nk为奇数,那么除以2之后为小数,所以应该 + 1 +1 +1 − 1 -1 1,答案为 1 1 1

代码

#include
#include
#include
#include
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

题目链接

题目原文

题目大意

有两个数组 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=aibi0aibiif ai>biif ai=biif 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
#include
#include
#include
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 题解_第2张图片

题目大意

给出长度为 n n n的数组,每个数都大于1。记数组中最小的数为minn,现在你可以将数组中任意两个 g c d = m i n n gcd=minn gcd=minn的数进行交换。求有没有可能使得整个数组变成不下降序列。

解题思路

显然minn可以和所有数进行交换,那就将minn作为交换的中间值。

解法

将数组中是minn的倍数的数提出来,直接排序(因为他们都可以通过minn进行交换)。然后从小到大插入提出来的位置。最后check一下数组,如果这个数组满足要求,那么就ok。

代码

#include
#include
#include
#include
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 题解_第3张图片

题目大意

给出一棵树,但没有边权。
给出一个数的因数形式(给出的数的乘积为k)。

现在你需要给每一条边赋值,使得所有每两个点之间通过的路径和最大,且边权需要满足以下要求:

  1. 每条边的边权必须大于0
  2. 所有边的边权之积为k
  3. 边权为1的边的数量尽可能地少

解题思路

显然我们需要将通过最多的边赋值最大,通过次数最低的边赋值最小。于是我们想到贪心。

解法

用树形dp求出每条边的通过次数,对于一条边i,它的通过次数等于它的子树大小*(n-它的子树大小)。然后再贪心求解。

注意m>n-1的情况!

代码

#include
#include
#include
#include
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;
}

你可能感兴趣的:(算法,Codeforces,算法,dfs,icpc)