• CF Round #631 div2 题解


    (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

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

  • 相关阅读:
    .NET性能调优 ---- 使用Visual Studio进行代码度量
    博客园程序源代码下载
    C#中 Newtonsoft.Json 高级用法
    C# 自定义Thread挂起线程和恢复线程
    看图知义,Winform开发的技术特点分析
    循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理
    循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理
    ABP框架中短信发送处理,包括阿里云短信和普通短信商的短信发送集成
    循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志
    循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/12637116.html
Copyright © 2020-2023  润新知