Codeforces Round #572 (Div. 2)(题解)

Codeforces Round #572 (Div. 2)(题解)

A. Keanu Reeves

题目大意

给出一段01序列,现希望将其分为尽可能少段使得每一段的0和1的数量都不相同

解题思路

分情况,如果原串0和1数量已经不同,则直接输出原串即可,如原串0和1的数量相同,则将原串分为两个串的第一个串为原串的第一个字符,第二个串为原串的剩下

AC代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	scanf("%d",&n);
	char s[105];
	scanf("%s",s+1);
	int z=0,o=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='0') z++;
		else o++;
	}
	if(o!=z)
	{
		puts("1");
		printf("%s\n",s+1);
	}
	else
	{
		printf("2\n");
		printf("%c %s",s[1],s+2);
	}
}

B. Number Circle

题目大意

给出一些数字,要求将数字狗造成一个环,使得这个环中每个数字的大小都小于这个数两侧的数的和。

解题思路

将给的数字进行排序,再将最大的数和次大的数字交换位置即可得出最容易满足条件的数环,此时只需要满足第三大的数字加上第二大的数字大于最大的数字即可,反之则无解

AC代码

#include<bits/stdc++.h>
using namespace std;
const int size=1e5+5;
int a[size];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	swap(a[n],a[n-1]);
	if(a[n]+a[n-2]>a[n-1])
	{
		puts("YES");
		for(int i=1;i<=n;i++) 
		{
			printf("%d%c",a[i],i==n?'\n':' ');
		}
	}
	else puts("NO");
		
}

C. Candies!

题目大意

给出一种操作:

给出一段长度为 2 n ( n ≥ 0 ) 2^n(n\ge0) 2nn0的序列,现将 a 2 i + 1 , a 2 i + 2 a_{2i+1},a_{2i+2} a2i+1,a2i+2换作 ( a 2 i + 1 + a 2 i + 2 ) m o d   10 (a_{2i+1}+a_{2i+2})mod\ 10 (a2i+1+a2i+2)mod 10,如果 a 2 i + 1 , a 2 i + 2 ≥ 10 a_{2i+1},a_{2i+2}\ge 10 a2i+1,a2i+210则奖励一颗糖果

现在有一序列设为s,则设一函数f(s),其为通过上述操作将原序列长度变为1的过程中最多可以获得多少的糖果。

本题的问题是,给出一段序列。现在有q个询问,每次询问给出一对l和r(保证 r − l + 1 = 2 n r-l+1=2^n rl+1=2n)问原序列的子序列[l,r]的f函数的函数值为多少

解题思路

对每个位置向后长度为2的次方的倍数预处理出答案即可。每个位置的某个长度的答案可以从这个位置这个长度的一半递推得到。具体见代码

AC代码

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const int size=1e5+5;
int s[size];
int ans[size][20];
int num[size][20];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
	for(int i=1;i<=n;i++) num[i][0]=s[i],ans[i][0]=0;
	for(int i=1;i<=int(log2(n));i++)
	{
		for(int j=1;j+(1<<i)-1<=n;j++)
		{
			num[j][i]=num[j][i-1]+num[j+(1<<(i-1))][i-1];
			ans[j][i]=ans[j][i-1]+ans[j+(1<<(i-1))][i-1];
			if(num[j][i]>=10)
			{
				num[j][i]%=10;
				ans[j][i]++;
			}
		}
	}
	int q;
	scanf("%d",&q);
	while(q--)
	{
		int r,l;
		scanf("%d%d",&l,&r);
		if(r==l)
		{
			if(s[l]>=10) puts("1");
			else puts("0");
		}
		else 
		{
			
			printf("%d\n",ans[l][int(log2(r-l+1+eps))]);
		}
	}
}

D1. Add on a Tree

题目大意

给出一颗树,现在可以任意选择两个叶子节点,为这两个叶子节点之间的简单路径上的所有的边加上一个或者减去一个任意的实数,现问给出的这棵树可否通过有限次操作使得树上的边的权值达到任意的组合状态。

解题思路

原题的题意即所有的边的权值是否可以最终都变成不同的值。如果想要对任意的边修改权值而不影响到其他边,则这条边就需要被叶子路径经过至少两次,这就要求除了叶子节点以外所有的点的度都要大于等于3

AC代码

#include<bits/stdc++.h>
using namespace std;
const int size=1e5+5;
int du[size];
int main()
{
	int n;
	scanf("%d",&n);
	memset(du,0,sizeof(du));
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		du[u]++,du[v]++;
	}
	if(n==2)
	{
		puts("YES");
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if(du[i]<=2&&du[i]!=1)
			{
				 puts("NO");
				 return 0;
			}
		}
		puts("YES");
	}
}

D2. Add on a Tree: Revolution

题目大意

和上题相似,不同的是现在给出一棵树,以及目标得到的权值(所有的权值都是互不相同且为偶数的)。问可否通过上面给出的操作得到这种树

解题思路

根据上题可知,如果想到所有的边可以叨叨互不相同的值则需要满足除了叶子节点所有的节点的度数都大于等于3,则对于一条边而言(先假设其两端的节点都不是叶子节点),则两个端点向着非另一个端点的方向至少有两个叶子节点,设两个端点分别在左右,则左节点向左的叶子节点中选出两个设为A,B,右节点向右的叶子节点中选出两个设为C,D,则只要AD=val/2,BC=val/2,AB=-val/2,CD=-val/2即可,如有一个端点为叶子节点,(假设为左节点)则使得A,B都为这个叶子节点,且A,B之间不再进行操作

AC代码

#include<bits/stdc++.h>
using namespace std;
const int size=1005;
struct Edge{
	int u,v,w;
	Edge(){}
	Edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector<Edge> e;
vector<int> G[size];
vector<int> x,y;
vector<Edge> ans;
int a,b,c,d;
void dfs(int v,int f,int mode)
{
	if(G[v].size()==1)
	{
		if(mode==0)
		{
			if(a==0) a=v;
			b=v;
		}
		if(mode==1)
		{
			if(c==0) c=v;
			d=v;
		}
	}
	for(auto u:G[v])
	{
		if(u==f) continue;
		dfs(u,v,mode);
	}
}
int main()
{
	int n,u,v,w;
	scanf("%d",&n);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		e.push_back(Edge(u,v,w));
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=1;i<=n;i++)
	{
		if(G[i].size()!=1&&G[i].size()<3)
		{
			puts("NO");
			return 0;
		}
	}
	puts("YES");
	for(auto ed:e)
	{
		u=ed.u,v=ed.v,w=ed.w;
		a=b=c=d=0;
		dfs(u,v,0);
		dfs(v,u,1);
		ans.push_back(Edge(a,c,w/2));
		ans.push_back(Edge(b,d,w/2));
		if(a!=b) ans.push_back(Edge(a,b,-w/2));
		if(c!=d) ans.push_back(Edge(c,d,-w/2));
	}
	printf("%d\n",ans.size());
	for(auto e:ans)
	{
		printf("%d %d %d\n",e.u,e.v,e.w);
	}
}
		
		

E. Count Pairs

题目大意

给出一个素数p,n个整数 a 1 , a 2 , a 3 , a 4 , . . . a n a_1,a_2,a_3,a_4,...a_n a1,a2,a3,a4,...an,和一个整数k。
问有多少组(i,j)( 1 ≤ i &lt; j ≤ n 1\le i&lt;j\le n 1i<jn)满足 ( a i + a j ) ( a i 2 + a j 2 ) ≡ k ( m o d   p ) (a_i+a_j)(a_i^2+a_j^2)\equiv k(mod\ p) (ai+aj)(ai2+aj2)k(mod p)

解题思路

( a i + a j ) ( a i 2 + a j 2 ) ≡ k ( m o d   p ) ( a i − a j ) ( a i + a j ) ( a i 2 + a j 2 ) ≡ ( a i − a j ) ∗ k ( m o d   p ) a i 4 − a j 4 ≡ a i k − a j k ( m o d   p ) a i 4 − a i k ≡ a j 4 − a j k ( m o d   p ) (a_i+a_j)(a_i^2+a_j^2)\equiv k(mod\ p)\\ (a_i-a_j)(a_i+a_j)(a_i^2+a_j^2)\equiv (a_i-a_j)*k(mod\ p)\\ a_i^4-a_j^4\equiv a_ik-a_jk(mod\ p)\\ a_i^4-a_ik\equiv a_j^4-a_jk(mod\ p) (ai+aj)(ai2+aj2)k(mod p)(aiaj)(ai+aj)(ai2+aj2)(aiaj)k(mod p)ai4aj4aikajk(mod p)ai4aikaj4ajk(mod p)

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
unordered_map<int,int> mp;
int main()
{
 	int n,p,k;
 	scanf("%d%d%d",&n,&p,&k);
 	LL a;
 	mp.clear();
 	long long ans=0;
 	for(int i=1;i<=n;i++)
 	{
 		scanf("%lld",&a);
 		int val=(a*a%p*a%p*a%p-a*k%p+p)%p;
 		ans+=(mp[val]++);
 	}
 	printf("%lld\n",ans);
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值