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)个人题解