codeforces #378 Div2 ABCD题解

来源:互联网 发布:万网域名解析 端口 编辑:程序博客网 时间:2024/06/06 14:16

做了几场CF的Div2级别的比赛,终于从这一场知道怎么上分了(因为自己很菜,还是1500+,所以上分很简单。。。)

先说说做题的心态:

A题B题,看完样例,看完特判,直接求手速,一般不会卡太多太难的数据

只需要保证:如果题目中有Hint好好看看,题目中有无法达成目标,然后需要输出-1或者无解信息的需要认真去想边界情况


然后CDEF的策略:

如果C和D题同分,那么先花上10分钟左右选题,把题目和样例读懂(这种比赛一般会是2个半小时6题甚至7题,我们的目标是保证3题,冲刺4题)

如果只有一个题有思路,那么没得挑

如果两个题在大概思路上都是会写的,而且觉得思路比较靠谱:那么我推荐:先做数据结构维护比较简单和熟悉的

(比如说这场的C和D)

C是一个看上去比较简单的构造题,然而需要先判断能否构造,再输出方案,还需要考虑到中间过程中节点位置和数目的变化,短时间不容易想清楚,比赛的时候先做的C题,幸好PP了(虽然最终挂了,但是给了我时间去写D)

D是一个我看错了题目的题:如果不看错题目,是个很简单的排序题


如果C和D不同分,那么我推荐硬着头皮做C题(因为只有2个小时,同时开2个题对我来说比较吃力,可能费力不讨好,一个都过不了)


如果还有能力和时间:

E题:如果觉得20分钟之内,能把代码写出来,而且比赛时间剩40分钟以上,那么我觉得去写是有意义的

有留给自己出样例,调试程序的时间

因为如果出不来这个题,不如把时间花在Lock了ABCD,然后去Hack别人的环节


当然,如果励志AK各种比赛的dalao

我这种弱菜就只能好好打自己的DIV2了,默默的不说话


如果愿意去Hack的:

我是建议先把C题和D题读完再去Hack:因为Hack其实是有风险的

在我认为我实力不够的情况下,把自己的A题和B题Lock了,而且Hack不到别人,自己的程序反而被别人Hack了不能再提交

那么这场就不用想着上分了


下面来认真说说这套题的ABCD四个题:

总体难度:A和B暴力模拟靠手速,C题有难度需要数学想法,D题看暴力思路

题目链接:codeforces733


733A

这个题没有太多可说的,比赛的时候出现了一个很搞笑的事:没有判断Y字母的可以PP

维护当前元音字母,找下一个元音字母就可以

#include<bits/stdc++.h>using namespace std;bool ok(char x){    if (x=='A'||x=='E'||x=='I'||x=='O'||x=='U'||x=='Y') return true;    return false;}char s[500];int main(){    int ans,n;    while(scanf("%s",s+1)!=EOF){        n=strlen(s+1);        ans=0;        int last=0;        for(int i=1;i<=n;i++)            if (ok(s[i])){                ans=max(ans,i-last);                //printf("%d\n",i-last);                last=i;            }        //printf("%d\n",n+1-last);        ans=max(ans,n+1-last);        printf("%d\n",ans);    }    return 0;}

733B

这个题也是个暴力题

求个和就好,然后再次扫一遍,每次求值去比较就好

细节点是要注意答案的初始化设为0是比较好的,因为最后如果有问题的话,也是要输出0的

#include<bits/stdc++.h>using namespace std;const int maxn=1e5+500;int n;int l[maxn],r[maxn];int suml,sumr;int tmpl,tmpr;int pos,ans;int main(){    //freopen("input.txt","r",stdin);    while(scanf("%d",&n)!=EOF){        suml=sumr=0;        for(int i=1;i<=n;i++){            scanf("%d%d",&l[i],&r[i]);            suml+=l[i];            sumr+=r[i];        }        pos=0;ans=abs(suml-sumr);        for(int i=1;i<=n;i++){            tmpl=suml-l[i]+r[i];            tmpr=sumr-r[i]+l[i];            if (abs(tmpl-tmpr)>ans){                pos=i;                ans=abs(tmpl-tmpr);            }        }        printf("%d\n",pos);    }    return 0;}

733C

这个题是自己比较自信的一个题:然后各种没有做好细节,带崩了

说下题意:

题目中会给n个数,这些数有其大小。大数可以把相邻的小数合并(大小是相对的)如果可以合并就可以一直合并

然后需要判断这n个数是不是有某个合并方案让其变成之后给的k个数

解释下样例:

61 2 2 2 1 225 5

看到5和5,说明(1 2 2)是一组,(2 1 2)是另外一组

(1 2 2)合并成5是有方案的,虽然(2 2)不能合并,但是先合并成(3 2)就是可以变成5的啦


51 1 1 3 332 1 6

再看这个,仍然是分组

(1 1)合并成2,无解

(1)就是对应1

(3 3)对应成6,无解

所以输出NO


所以,整体思路如下:

首先,将这n个数分成k组,这k组的和要与其输入的k个值一一对应

然后,如果每个组的数不是都相等(意味着有某个数可以不断的进行合并然后变成给定的值),那么输出YES,否则输出NO

这样是我的第一次想法,有HACK点:

A:没有判断n个数的和是不是等于k个数的和

B:每个组的数是不是都相等代码上怎么实现:如果某个组里只有一个元素,这个时候是可以构造的

C:最大值是怎么找到的,周围是不是都是最大值


结合上所有点HACK点,加上各种特判,说说自己怎么构造的:

在每个组里,找到可以去贪心的最大值:

可以的概念是:左边或者右边有值,而且这个值比我要小

贪心的概念是:如果找到的是左边:那么先把左边的数全部合并完毕;否则亦然

然后就是最麻烦的合并节点了:其实很好想清楚

当前已经处理好了m-1个组,现在在处理第m组,那么第m组的第一个数原来标号是什么?现在标号是什么?

因为前m-1个组已经合并好了,那么现在只占m-1个位置

原来有多少个位置,就看每个组里有多少个元素,加起来求个和就好了


那么标号的变化呢?

往左边吃,坐标吃完是要减1的。比如(1 2),吃完之后变成了(3),坐标有变化

往右边吃,坐标吃完是不变的。比如(2 1),吃完之后变成了(3),坐标没有变化


代码如下:

#include<bits/stdc++.h>using namespace std;const int maxn=550;int n,k;int sum[maxn];int sumpoint[maxn];int a[maxn];struct node{    int l,r;    int sum;}b[maxn];bool check(){    for(int i=1;i<=k;i++){        int len=b[i].r-b[i].l+1,tmp=0;        if (len==1) continue;        for(int j=b[i].l;j<=b[i].r;j++)            if (a[j]==a[b[i].l]) tmp++;        if (tmp==len) return false;    }    return true;}void print(int pos){    int i,maxnum=0,maxnumpos,len=b[pos].r-b[pos].l;    for(i=b[pos].l;i<=b[pos].r;i++)    if (a[i]>maxnum) maxnum=a[i];    for(i=b[pos].l;i<=b[pos].r;i++)    if (a[i]==maxnum){        if (i==b[pos].l){            if (a[i+1]<maxnum){                maxnumpos=i;                break;            }        }        else if (i==b[pos].r){            if (a[i-1]<maxnum){                maxnumpos=i;                break;            }        }        else{            if (a[i-1]<maxnum||a[i+1]<maxnum){                maxnumpos=i;                break;            }        }    }    i=maxnumpos;    if (i==b[i].r||(a[i]>a[i-1]&&i!=b[i].l)){        while(i!=b[pos].l){            printf("%d L\n",i-sumpoint[pos-1]);            i--;len--;        }        while(len){            printf("%d R\n",i-sumpoint[pos-1]);            len--;        }    }    else{        while(i!=b[pos].r){            printf("%d R\n",i-sumpoint[pos-1]);            len--;b[pos].r--;        }        while(i!=b[pos].l){            printf("%d L\n",i-sumpoint[pos-1]);            i--;len--;        }    }}int main(){    //freopen("input.txt","r",stdin);    while(scanf("%d",&n)!=EOF){        int sumk=0;        sum[0]=0;sumpoint[0]=0;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            sum[i]=a[i]+sum[i-1];        }        scanf("%d",&k);        for(int i=1;i<=k;i++){            scanf("%d",&b[i].sum);            sumk+=b[i].sum;        }        if (sumk!=sum[n]){            puts("NO");            continue;        }        int s,i=1,j=1;        for(s=1;s<=n;s++)        if (sum[s]-sum[j-1]==b[i].sum){            b[i].l=j;            b[i].r=s;            sumpoint[i]=b[i].r-b[i].l+sumpoint[i-1];            j=s+1;            i++;        }        if (i!=k+1){            puts("NO");            continue;        }        /*        else{            for(i=1;i<=k;i++)                printf("%d %d %d\n",b[i].l,b[i].r,b[i].sum);        }        */        if (check()){            puts("YES");            for(int i=1;i<=k;i++)                print(i);        }        else puts("NO");    }    return 0;}


733D

题目有句话特别重要:(自己傻逼了没看到,写了三个排序,乱搞了好久,然后WA7了,又重写,至少浪费了500分)

In such gluing it is allowed to rotate and flip the stones in any way.

每个长方体是可以翻转的!

那么,我们可以按照x>=y>=z的方式来排序,如果(x,y)相同的,我们就合并z

因为要是球体,所以维护一个最大值就好,每次与min(x,y,z)比较取较大值


代码:

#include<bits/stdc++.h>using namespace std;const int maxn=1e5+500;int ans1,ans2,maxnum;struct node{    int x,y,z,id;}a[maxn];int cmp(node aa,node bb){    if (aa.x==bb.x&&aa.y==bb.y) return aa.z<bb.z;    if (aa.x==bb.x) return aa.y<bb.y;    return aa.x<bb.x;}int Max,Min,n;int main(){    //freopen("input.txt","r",stdin);    while(scanf("%d",&n)!=EOF){        maxnum=0;        for(int i=1;i<=n;i++){            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);            a[i].id=i;            Max=max(a[i].x,max(a[i].y,a[i].z));            Min=min(a[i].x,min(a[i].y,a[i].z));            if (Min>maxnum){                maxnum=Min;                ans1=ans2=i;            }            a[i].y=a[i].x+a[i].y+a[i].z-Max-Min;            a[i].x=Max;            a[i].z=Min;        }        sort(a+1,a+n+1,cmp);        //for(int i=1;i<=n;i++)        //    printf("%d %d %d\n",a[i].x,a[i].y,a[i].z);        for(int i=2;i<=n;i++)        if (a[i].x==a[i-1].x&&a[i].y==a[i-1].y){            Min=min(a[i].x,min(a[i].y,a[i].z+a[i-1].z));            if (Min>maxnum){                maxnum=Min;                ans1=a[i].id;                ans2=a[i-1].id;            }        }        if (ans1==ans2)            printf("1\n%d\n",ans1);        else            printf("2\n%d %d\n",ans1,ans2);    }    return 0;}


0 0
原创粉丝点击