Codeforces Codeforces Round #452 (Div. 2)(899A-899F) 题解

来源:互联网 发布:泰迪体质 知乎 编辑:程序博客网 时间:2024/06/18 11:44

总结

这是我上紫后第一次去打div2,感觉十分的休闲。鉴于我最后不够时间写F的惨痛经历,我决定下次打div2的时候要从后往前做。
达成成就:get到了人生的第一次被hack,这里截图以作留念。
这里写图片描述
由于这是div2,总体来讲并不难,有很多人1h左右就已经ak了。但由于种种原因我用了1h才搞完abc,果然还是要加强对细节题的快速处理。

A. Splitting in Teams

送分题,怎么做都行。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=200005;int n,a[N],t[3];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    n=read();    for (int i=1;i<=n;i++)    {        int x=read();        t[x]++;    }    int ans=min(t[1],t[2]);    t[1]-=ans;t[2]-=ans;    ans+=t[1]/3;    printf("%d",ans);    return 0;}

B. Months and Years

由于n很小所以暴力枚举开始月份然后扫一遍即可。一开始被hack掉是因为我没判断数据中有两个连续闰年的情况。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=45;int n,a[N],d[12]={31,28,31,30,31,30,31,31,30,31,30,31},t[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    n=read();    for (int i=1;i<=n;i++) a[i]=read(),t[a[i]]++;    if (t[29]>1) {puts("NO");return 0;}    for (int i=0;i<12;i++)    {        int flag=0;        for (int now=i,j=1;j<=n;j++,now=(now+1)%12)            if (now==1)            {                if (a[j]!=28&&a[j]!=29) {flag=1;break;}            }            else            {                if (a[j]!=d[now]) {flag=1;break;}            }        if (!flag) {puts("YES");return 0;}    }    puts("NO");    return 0;}

C. Dividing the numbers

这题的水法有很多。我的方法是从大到小贪心选数来逼近s/2,其中s表示1到n的和。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=60005;int n,ans[N];void solve(LL s){    int tot=0;LL w=0;    for (int i=n;i>=1;i--)        if (s>=i) s-=i,ans[++tot]=i,w+=i;    printf("%I64d\n%d ",abs((LL)n*(n+1)/2-w*2),tot);    for (int i=tot;i>=1;i--) printf("%d ",ans[i]);}int main(){    scanf("%d",&n);    LL s=(LL)n*(n+1)/2;    solve((s+1)/2);    return 0;}

D. Shovel Sale

这题好就好在限定的数是9,要是换成其他数的话估计就会麻烦很多,至少对我的方法来说是这样的。数位dp,设f[i,j,0/1,0/1]表示有多少数对(x,y)满足(x>=y)且从高到底做到第i位,从第i位开始连续9的个数为j,x是否卡着n的上界,x是否等于y。由于这里要求的是9,不难发现从最低位到第len位都是不用进位的,其中len表示后缀9的长度,所以这里转移的时候也不用考虑进位的问题。转移完之后我还dp了一次,是为了减掉y=0的情况。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;int n,a[15],g[15][2],a1;LL f[15][15][2][2];int work(int mx){    g[a1+1][1]=1;    for (int i=a1+1;i>mx+1;i--)    {        if (g[i][0]) g[i-1][0]+=g[i][0]*10;        if (g[i][1])        {            g[i-1][1]+=g[i][1];            g[i-1][0]+=g[i][1]*a[i-1];        }    }    int ans=0,flag=0;    for (int i=1;i<=mx;i++) if (a[i]!=9) {flag=1;break;}    if (!flag) return g[mx+1][0]+g[mx+1][1];    else return g[mx+1][0];}int main(){    scanf("%d",&n);    int tmp=n;    while (tmp) a[++a1]=tmp%10,tmp/=10;    f[a1+1][0][1][1]=1;    for (int i=a1+1;i>1;i--)        for (int j=0;j<=a1;j++)        {            if (f[i][j][0][0])            {                LL w=f[i][j][0][0];                for (int x=0;x<=9;x++)                    for (int y=0;y<=9;y++)                        if (x+y==9) f[i-1][j+1][0][0]+=w;                        else f[i-1][0][0][0]+=w;            }            if (f[i][j][0][1])            {                LL w=f[i][j][0][1];                for (int x=0;x<=9;x++)                {                    f[i-1][0][0][1]+=w;                    for (int y=0;y<x;y++)                        if (x+y==9) f[i-1][j+1][0][0]+=w;                        else f[i-1][0][0][0]+=w;                }            }            if (f[i][j][1][0])            {                LL w=f[i][j][1][0];                for (int x=0;x<=9;x++)                    if (x+a[i-1]==9) f[i-1][j+1][1][0]+=w;                    else f[i-1][0][1][0]+=w;                for (int x=0;x<a[i-1];x++)                    for (int y=0;y<=9;y++)                        if (x+y==9) f[i-1][j+1][0][0]+=w;                        else f[i-1][0][0][0]+=w;            }            if (f[i][j][1][1])            {                LL w=f[i][j][1][1];                f[i-1][0][1][1]+=w;                for (int x=0;x<a[i-1];x++)                    if (x+a[i-1]==9) f[i-1][j+1][1][0]+=w;                    else f[i-1][0][1][0]+=w;                for (int x=0;x<a[i-1];x++)                {                    f[i-1][0][0][1]+=w;                    for (int y=0;y<x;y++)                        if (x+y==9) f[i-1][j+1][0][0]+=w;                        else f[i-1][0][0][0]+=w;                }            }        }    int mx=0;    for (int i=a1;i>=0;i--) if (f[1][i][0][0]+f[1][i][1][0]>0) {mx=i;break;}    if (!mx) {printf("%I64d",(LL)n*(n-1)/2);return 0;}    printf("%I64d",f[1][mx][0][0]+f[1][mx][1][0]-(LL)work(mx));    return 0;}

E. Segments Removal

直接用线段树来维护最长连续序列同时支持删除即可。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=200005;int n,a[N];struct tree{int mx,pl,pr,s,l,r,sl,sr,ppl,ppr;}t[N*5];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void updata(int d,int l,int r){    int mid=(l+r)/2;    if (!t[d*2].mx) t[d]=t[d*2+1];    else if (!t[d*2+1].mx) t[d]=t[d*2];    else    {        t[d].s=t[d*2].s+t[d*2+1].s;        if (t[d*2].sl==t[d*2].s&&t[d*2].l==t[d*2+1].l) t[d].sl=t[d*2].sl+t[d*2+1].sl,t[d].l=t[d*2].l,t[d].ppl=t[d*2+1].ppl;        else t[d].sl=t[d*2].sl,t[d].l=t[d*2].l,t[d].ppl=t[d*2].ppl;        if (t[d*2+1].sr==t[d*2+1].s&&t[d*2+1].r==t[d*2].r) t[d].sr=t[d*2+1].sr+t[d*2].sr,t[d].r=t[d*2+1].r,t[d].ppr=t[d*2].ppr;        else t[d].sr=t[d*2+1].sr,t[d].r=t[d*2+1].r,t[d].ppr=t[d*2+1].ppr;        t[d].mx=t[d*2].mx;t[d].pl=t[d*2].pl;t[d].pr=t[d*2].pr;        if (t[d*2].r==t[d*2+1].l&&t[d*2].sr+t[d*2+1].sl>t[d].mx) t[d].mx=t[d*2].sr+t[d*2+1].sl,t[d].pl=t[d*2].ppr,t[d].pr=t[d*2+1].ppl;        if (t[d*2+1].mx>t[d].mx) t[d].mx=t[d*2+1].mx,t[d].pl=t[d*2+1].pl,t[d].pr=t[d*2+1].pr;    }}void build(int d,int l,int r){    if (l==r)    {        t[d].sl=t[d].sr=1;        t[d].l=t[d].r=a[l];        t[d].mx=1;        t[d].pl=t[d].pr=t[d].ppl=t[d].ppr=l;        t[d].s=1;        return;    }    int mid=(l+r)/2;    build(d*2,l,mid);build(d*2+1,mid+1,r);    updata(d,l,r);}void ins(int d,int l,int r,int x,int y){    if (x>y) return;    if (l==x&&r==y)    {        t[d].l=t[d].r=t[d].sl=t[d].sr=t[d].mx=t[d].pl=t[d].pr=t[d].s=t[d].ppl=t[d].ppr=0;        return;    }    int mid=(l+r)/2;    ins(d*2,l,mid,x,min(y,mid));    ins(d*2+1,mid+1,r,max(x,mid+1),y);    updata(d,l,r);}int main(){    n=read();    for (int i=1;i<=n;i++) a[i]=read();    build(1,1,n);    int ans=0;    while (t[1].mx)    {        ins(1,1,n,t[1].pl,t[1].pr);        ans++;    }    printf("%d",ans);    return 0;}

F. Letters Removing

一开始想的是开62棵线段树,后来发现只用开一棵线段树来支持找对应区间,用62个set来找到删除的位置即可。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<set>using namespace std;const int N=200005;int n,m;char s[N];struct tree{int s;}t[N*5];set<int> w[65];bool f[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int get_num(char c){    if (c>='a'&&c<='z') return c-'a'+1;    if (c>='A'&&c<='Z') return c-'A'+27;    return c-'0'+53;}void build(int d,int l,int r){    t[d].s=r-l+1;    if (l==r) return;    int mid=(l+r)/2;    build(d*2,l,mid);build(d*2+1,mid+1,r);}void ins(int d,int l,int r,int x){    t[d].s--;    if (l==r) return;    int mid=(l+r)/2;    if (x<=mid) ins(d*2,l,mid,x);    else ins(d*2+1,mid+1,r,x);}int query(int d,int l,int r,int k){    if (l==r) return l;    int mid=(l+r)/2;    if (t[d*2].s>=k) return query(d*2,l,mid,k);    else return query(d*2+1,mid+1,r,k-t[d*2].s);}int main(){    n=read();m=read();    scanf("%s",s+1);    for (int i=1;i<=n;i++)    {        int x=get_num(s[i]);        w[x].insert(i);    }    build(1,1,n);    while (m--)    {        int l=read(),r=read();        char ch[2];scanf("%s",ch);        int x=get_num(ch[0]);        l=query(1,1,n,l);r=query(1,1,n,r);        set<int>::iterator it=w[x].lower_bound(l);        while (it!=w[x].end()&&(*it)<=r)        {            ins(1,1,n,(*it));f[(*it)]=1;            w[x].erase(it),it;it=w[x].lower_bound(l);        }    }    for (int i=1;i<=n;i++) if (!f[i]) putchar(s[i]);    return 0;}
原创粉丝点击