Codeforces Round #529 (Div. 3) ABCD题解

A. Repeating Cipher

简单思维题

题目大意:给你一个经过加密的字符串S,S = S1S2S3.....;而Si意味着这个字母他会书写i次;列如baabbb,这是加密后的样子加密前就是bab;题目需要你输出加密前的字符串;

思路:用一个中间变量t充当i,每解密一个字母后,就t++;然后我循环输出的s[i+=t],每次就输出加密后Si的最后一个字母。就是需要的答案了。

#include
#include
#include
using namespace std;
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		char s[60];
		scanf("%s",s);
		int j=1;
		for(int i=0;i

 

 

B. Array Stabilization

B题也是简单思维题,一开始题目没读懂,WA了一发

题目大意:给你一串数,你可以删掉其中任意一个数,使得剩下的数中,最大值减最小值最小。

思路:第一发WA在无脑删最后一个数了。先进行一次升序排序,如果这个串是1,6,7,那我肯定得删掉第一个数;如果是1,2,7,那肯定得删掉第一个数。所以就是找倒数第二个数减第一个数,与倒数第一个数减第二个数之间的最小值。注意一定要先排序。

#include
#include
using namespace std;
const int maxn = 1e5+10;
int a[maxn];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;i++)
	    scanf("%d",&a[i]);
	    sort(a+1,a+n+1);
	    if(n==2) printf("%d\n",0);
	    else{
	    	int minm = min(a[n]-a[2],a[n-1]-a[1]);
	    	printf("%d\n",minm);
		}
	}
 } 

 

C. Powers Of Two

在愉快的A了前面两道题后,自闭时间到了。C题是一道二进制相关的题目

无论给你一个什么类型的数,奇数,偶数,它总能分解成以下形式:

x = 2^a1+2^a2+2^a3.+。。;仔细想一下,是不是就是把这个数化解成二进制的过程。那我每次处以2,这些数就会一步步的变成1与剩下的偶数相加就是奇数了,也就是说如果这个数x被处以2^n后得到的是奇数的话,那就说明这个数就是构成x中的一个2^ai,而且这个ai就等于n。那会不会有两个相同2^ai存在呢?答案是不会,这两个会组成2^(ai+1)。如果是三个呢,那就会得到2^ai+2^(ai+1);所以如果得到的是奇数,就用数组标记为1,再用一个cnt记录其个数。然后就是要满足题目个数要求,那就是高位每次可以分解成两倍的低位,每次我就只把一个次方大于1的分解成两个次方减1的,这样我每次分解就可以多得到一个数。

 

#include
#include
#include
#include 
using namespace std;
const int N=1e5;

int main(){
	int n,k,cnt=0,j=0;//cnt记录能分解的个数 
	scanf("%d%d",&n,&k);
	int a[100];
	memset(a,0,sizeof(a)); 
	for(int i=0;i<30;i++){
		if((n>>i)&1){
			a[i]=1;	
			cnt++;
		}
	}
	
	if(nk){// 如果cnt大于k,说明这个数分解的个数最少都要大于k个;n小于k,也就是n全化为1都要小于k个 
		puts("NO");
		return 0;
	}
	else {
		while(cnt0){
					a[i]--;
					a[i-1]+=2;
					break;
				}			
			}
	}
	puts("YES");
	for(int i=0;i<30;i++){
			k--;
			while(a[i]){
				a[i]--;
				if(k)printf("%d ",(int)pow(2,i));
			    else printf("%d\n",(int)pow(2,i));
			}	
	}					
	}	
} 

这道题是赛后看周大佬代码看懂的,代码也是他的。其实当时比赛的时候有想过把这个数以二进制进行分解,无奈对二进制

的一些性质还是不够熟悉,所以想歪了。

 

D. Circular Dance

题目有点难读懂。直接看样例吧。

5
3 5
1 4
2 4
1 5
2 3
在这组数据中,第一个人的两个孩子是3和5,第二人的两个孩子是1,4;第三个人的两个孩子是2和4,第四个人的两个孩子是1,5;第五个人的孩子是2和3,如果我从第一个人出发,那我只要查询他(父亲)左孩子的两个孩子是不是等于他(父亲)的右孩子,如果不是的话,那肯定父亲的右孩子会等于父亲左孩子的其中一个孩子。所以从1开始,这么依次循环查找下去就行了。但是要注意的是一定要设置一个标记数组来记录这个点是否走过,不然就会重复输出。

#include
#include
#include
using namespace std;
const int maxn = 2e5+10;
struct node{
	int l,r;
}a[maxn];
int vis[maxn];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].l,&a[i].r);
		memset(vis,0,sizeof(vis));
		vis[1]=1;//直接从第一个点开始走
		int t=1;
		n-=1; 
		printf("%d ",t);
		while(n--)
		{
			if((a[a[t].l].l==a[t].r||a[a[t].l].r==a[t].r)&&!vis[a[t].l])
			{
				t=a[t].l;
				vis[t]=1;
				printf("%d ",t);
			}
			else{
				t=a[t].r;
				vis[t]=1;
				printf("%d ",t);
			}
		}
		puts(" ");
	}
}

 

你可能感兴趣的:(CF)