CF Round #631 题解

Posted huangdalaofighting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF Round #631 题解相关的知识,希望对你有一定的参考价值。

(Codeforces) (Round) (631)

A.Dreamoon and Ranking Collection

题目大意:

(n)轮比赛,每轮比赛排名已经给出,还可以进行额外的(m)场比赛
问:所有比赛进行完后,最多可以收集到从(1)开始的多少个连续名次

题解:

用一个数组统计一下排名的出现情况,然后扫一遍添加(m)个缺失名次即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
	int i,j,k,n,a,x,t,s[105],ans,mmax;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&x);
		memset(s,0,sizeof(s));
		ans=0;mmax=0;
		for(i=1;i<=n;i++){scanf("%d",&a);s[a]=1;mmax=max(mmax,a);}
		for(i=1;i<=mmax;i++){
			if(s[i]){ans=i;continue;}
			else if(s[i]==0&&x){x--;s[i]=1;ans=i;}
			else if(s[i]==0&&x==0){ans=i;break;}
		}
		while(s[ans]==1)ans++;
		ans+=x;
		ans--;
		printf("%d
",ans);
	}
	return 0;
}

B. Dreamoon Likes Permutations

题目大意:

给出(n)和长度为(n)的一个数列,可将其分为左右两部分,问有多少种分法,使得左右两部分都为从(1)开始的一个排列。输出方案数以及全部方案。

题解:

从左往右和从右往左各扫一次,处理出数组(l_1)(l_2),分别表示从第(1)位和第(n)位到第(i)位的所有数是否构成一个排列。然后枚举断点,如果左右两侧都是一个排列,那么当前断点就是一个方案,输出即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int t,n,a[200005],mmax,s1[200005],s2[200005],l1[200005],l2[200005];
void doit(){
	int i,j;
	mmax=0;
	for(i=1;i<=n;i++){
		mmax=max(mmax,a[i]);
		s1[a[i]]++;
		if(s1[a[i]]==1&&mmax==i)l1[i]=1;
		else if(s1[a[i]]>=2)break;
	}
	mmax=0;
	for(i=n;i>=1;i--){
		mmax=max(mmax,a[i]);
		s2[a[i]]++;
		if(s2[a[i]]==1&&mmax==n-i+1)l2[i]=1;
		else if(s2[a[i]]>=2)break;
	}
}
int main(){
	int i,j;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		memset(s1,0,sizeof(s1));
		memset(s2,0,sizeof(s2));
		memset(l1,0,sizeof(l1));
		memset(l2,0,sizeof(l2));
		for(i=1;i<=n;i++){scanf("%d",&a[i]);}
		doit();
		int ans=0;
		for(i=1;i<n;i++)
			if(l1[i]&&l2[i+1])ans++;
		if(ans==0)printf("%d
",ans);
		else{
			printf("%d
",ans);
			for(i=1;i<n;i++)
				if(l1[i]&&l2[i+1])
					printf("%d %d
",i,n-i);
		}
	}
	return 0;
}

C. Dreamoon Likes Coloring

题目大意:

(n)个格子,(m)次染色次数,每次染色宽度为(l_i),颜色为(i)
后染的颜色会覆盖原来的颜色
求一种染色方案使得每个格子都有颜色并且最后每个颜色都要出现
若无方案则输出(-1)

题解:

1.每个颜色至少要占一个格子,那么在第(i)个颜色涂上去之前,必定有(i-1)个格子已经有颜色了,因此(n-li<i-1)时必定无解。
2.总长度(<n)时必定无解。
3.其他情况均为有解情况,为获得方案,只需先默认第i个颜色从第i个格子开始涂。然后再贪心的将部分颜色往后面挪以填充未染色的格子即可。
ps.代码中是从后往前图的颜色

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long lol;
lol n,m,l[100005],sum,ans[100005];
int main(){
	lol i,j;
	scanf("%lld%lld",&n,&m);
	for(i=1;i<=m;i++){scanf("%lld",&l[i]);sum+=l[i];}
	for(i=1;i<=m;i++)
		if(n-l[i]<i-1){
			printf("-1
");
			return 0;
		}
	if(sum<n){
		printf("-1
");
		return 0;
	}
	lol len=m+l[m]-1,need=n-len,place=n-l[m]+1;
	for(i=m;i>=1;i--){
		ans[i]=place;
		if(need==0)place--;
		else{ 
			place-=min(l[i-1]-1,need)+1;
			need-=l[i-1]-1;
			if(need<0)need=0;
		}
	}
	for(i=1;i<=m;i++)
		printf("%d ",ans[i]);
	printf("
");
	return 0;
}

D. Dreamoon Likes Sequences

题目大意:

对于每组数据给出两个整数(d)(m)
求满足下列条件的数列(a_n)的个数对(m)取模的结果
1.(1≤a_1<a_2<?<a_n≤d)
2.(a_n)的前缀异或和(b_n)也为单调递增数列

题解:

由异或运算得到本题应从二进制角度来思考。
由异或和单调递增可知,数列(a_n)的最高位单调递增。
于是讨论二进制最高位的位数:
1.位数为(1)时,有(1)
2.位数为(2)时,有(2)
3.位数为(3)时,有(4)
...(以此类推)
故答案为(ans=(1+1)*(2+1)*(4+1)...-1)
ps.(+1)是因为当前数可以不取,(-1)是因为要减去全部都不取的情况。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long lol;
lol n,mod,t;
int main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&mod);
		lol ans=1%mod,x=1;
		while(x<=n){
			ans=(ans*(min(x,n-x+1)+1))%mod;
			x<<=1;
		}
		ans--;
		ans%=mod;
		while(ans<0)ans+=mod;
		printf("%lld
",ans);
	}
	return 0;
}

E. Drazil Likes Heap

题目大意:

给定一个层数为(h)的满二叉大根堆,再给定一个整数(g)
每次操作删除堆中的一个数。
求一个删除堆中元素的方案,使得:
1.最后得到的堆为一个(g)层的满二叉大根堆。
2.该堆的元素和最小。
输出最小的和以及删除方案。

题解:

不难得到以下结论:
1.每次删除一个节点,由它大儿子和大孙子组成的链的深度(-1)
2.一个节点不可删,当且仅当它大儿子和大孙子等组成的链的深度等于(g)
3.一个节点不可删,那么它的大儿子也不可删。由它大儿子和大孙子组成的链都不能删。
于是得到贪心算法,如果根节点能删则删,否则把左右儿子当作根分别进行删除操作。
这样能够保证随后得到的堆的元素和是最小的。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll(x) (x<<1)
#define rr(x) (x<<1|1)
using namespace std;
typedef long long lol;
int n,m,t,h,g,cnt,a[2500000],ans[2500000];
lol sum;
void del(int x){
	if(a[ll(x)]==0&&a[rr(x)]==0)a[x]=0;
	else{
		if(a[ll(x)]>a[rr(x)]){
			a[x]=a[ll(x)];
			del(ll(x));	
		}
		else{
			a[x]=a[rr(x)];
			del(rr(x));	
		}
	}
}
int get_depth(int x,int depth){
	if(a[x]==0)return depth-1;
	if(a[ll(x)]>a[rr(x)])return get_depth(ll(x),depth+1);
	else return get_depth(rr(x),depth+1);
}
void dfs(int x,int depth){
	if(a[x]==0)return;
	while(get_depth(x,depth)>m){del(x);ans[++cnt]=x;}
	dfs(ll(x),depth+1);
	dfs(rr(x),depth+1);
}
int main(){
	int i;
	scanf("%d",&t);
	while(t--){
		cnt=0;sum=0;
		scanf("%d%d",&n,&m);
		h=(1<<n)-1;g=(1<<m)-1;
		for(i=1;i<=h*2+1;i++)a[i]=0;
		for(i=1;i<=h;i++)scanf("%d",&a[i]);
		dfs(1,1);
		for(i=1;i<=g;i++)sum+=a[i];
		printf("%lld
",sum);
		for(i=1;i<=cnt;i++)
			printf("%d ",ans[i]);
		printf("
");
	}
	return 0;
}

BBT

没啥,就是觉得自己菜的一批





























以上是关于CF Round #631 题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #631 (Div. 2) - Thanks, Denis aramis Shitov!

Codeforces Round #631 (Div. 2) D.Dreamoon Likes Sequences

# Codeforces Round #529(Div.3)个人题解

codeforces比赛题解#915 Educational CF Round 36

竞赛题解 - CF Round #524 Div.2

CF Educational Round 51 题解