• Codeforces乱刷集合


    发这篇博客的目的是因为刷了些水题,但又有一些不错的地方可以加以借鉴....然后又不想一个一个发....

    Codeforces731A

    题目大意:给出一个26个字母的环,初始指向a,可以顺时针转或者逆时针转,给出一个字符串求最少转几次能得到他。

    题解:傻逼模拟。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    char S[100000];
    long long ans;
    int main()
    {
        scanf("%s",S+1); int len=strlen(S+1);
        int now,last,a; last='a';
        for (int i=1; i<=len; i++)
            {
                now=S[i];
                if (now>last) a=now-last; else a=last-now;
                ans+=min(a,26-a);
                last=now;
            }
        printf("%lld
    ",ans);
        return 0;
    }
    731A

    Codeforces731B

    题目大意:给出一个序列,你可以进行两种操作,1.一个位置-2;2.相邻两个位置-1;问是否可以恰好使所有数减到0。

    题解:贪心,因为最左边的相邻的只有它右边一个,所以可以从最左边的开始搞,注意不会减到0即可。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define N  200005
    inline 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 n,a[N],f[N];
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        a[1]%=2;
        for(int i=1;i<=n;i++){
            a[i]-=a[i-1];
            if(a[i] < 0) { puts("NO"); return 0; }
            a[i]%=2;
        }
        if(a[n]) puts("NO"); else puts("YES");
        return 0;
    }
    731B

    Codeforces731C

    题目大意:给出一个序列,每个位置有一个颜色,再给出一些区间要求这些区间中的颜色必须全都一样,求最少需要改变这个序列中的多少个位置,能使所有区间满足。

    题解:可以用并查集搞一下,或者用连通分支搞一下。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline 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 N,M,K,size,maxx,ans;
    struct data{int l,r,f;}a[200010];
    bool cmp(data x,data y) {return x.l==y.l? x.r<y.r : x.l<y.l;}
    struct EdgeNode{int next,to;}edge[400010];
    int head[200010],cnt=1;
    int st[200010],top;
    inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    bool visit[200010];
    int num[200010],c[200010];
    void work(int x)
    {
        /*printf("%d
    ",x);*/
        visit[x]=1; size++; num[c[x]]++; st[++top]=x;
        if (num[c[x]]>maxx) maxx=num[c[x]];
        for (int i=head[x]; i; i=edge[i].next) if (!visit[edge[i].to]) work(edge[i].to);
    }
    void clear()
    {
        for (int i=1; i<=top; i++) num[c[st[i]]]--; top=0;
    }
    int main()
    {
        N=read(),M=read(),K=read();
        for (int i=1; i<=N; i++) c[i]=read();
        for (int i=1; i<=M; i++) a[i].l=read(),a[i].r=read(),InsertEdge(a[i].l,a[i].r);
        for (int i=1; i<=N; i++)
            if (!visit[i]) maxx=0,size=0,work(i),ans+=size-maxx,clear();/*,printf("a  %d
    ",i)*/
        printf("%d
    ",ans);    
        return 0;
    }
    731C

    Codeforces731D

    题目大意:给出许多个序列,每次操作可以使这些数列中所有数+1,当一个数超过C后会还原成0,求最小需要几次操作后,满足给出的这些序列的按读入顺序且按字典序单调增,不行则输出-1。

    题解:考虑每个序列和它前一个数列比较,如果能够比它前一个数列递增,能够得到一段满足的操作数的区间,然后对所有区间求交算答案即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    inline 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 N,C,a[2][500010],len[500010],x;
    struct data{int l,r;}seg[1000010]; int cnt;
    inline bool cmp(data A,data B) {return A.l==B.l? A.r<B.r : A.l<B.l;}
    int main()
    {
        N=read(),C=read();
        x=0;
        for (int i=1; i<=N; i++,x^=1)
            {
                len[i]=read(); for (int j=1; j<=len[i]; j++) a[x][j]=read();
                if (i!=1)
                    {
                        int le=min(len[i],len[i-1]),pos=0;
                        for (int j=1; j<=le; j++) 
                            if (a[x][j]==a[x^1][j]) continue; else {pos=j; break;}
                        if (!pos && len[i]<len[i-1]) {puts("-1"); return 0;}
                        if (pos) 
                            if (a[x][pos]>a[x^1][pos]) 
                                seg[++cnt]=(data){C+1-a[x][pos],C-a[x^1][pos]};
                            else 
                                seg[++cnt]=(data){0,C-a[x^1][pos]},seg[++cnt]=(data){C+1-a[x][pos],C+1};
                    }
            }
        for (int i=1; i<=cnt; i++) if (seg[i].l>seg[i].r) swap(seg[i].l,seg[i].r);
    //    for (int i=1; i<=cnt; i++) printf("%d %d
    ",seg[i].l,seg[i].r);
        sort(seg+1,seg+cnt+1,cmp);
        int pos=0;
        for (int i=1; i<=cnt; i++)
            if (pos<seg[i].l) break;
                else pos=max(pos,seg[i].r+1);
        printf("%d
    ",(pos<=C)? pos:-1);
        return 0;
    }
    731D

    Codeforces731E

    题目大意:给出一个游戏,首先由一个数列,每次可以从左边开始选择一段数(>2个数)合并,并得到这段的分数,只剩一个数时结束,问双方都执行最优策略的时候,游戏结束时A最多比B多多少分。

    题解:比较容易的dp,可以用前缀和优化,记录一下后缀最大值。dp的方程是$dp[i]=max(dp[i],sum[j]-dp[j])$,然而dp的值完全不用记录,可以直接扫一遍。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int N,a[200010],s[200010],ans;
    int main()
    {
        scanf("%d",&N); for (int i=1; i<=N; i++) scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
        ans=s[N]; for (int i=N-1; i>1; i--) ans=max(ans,s[i]-ans); printf("%d
    ",ans);
        return 0;
    }
    731E

    Codeforces731F

    题目大意:给一个序列,问从序列中找一个数,把不小于它的数变成它或者它的倍数,并使得这些数的和最大

    题解:可以直接处理前缀和后暴力更新答案,之所以暴力的复杂度非常科学,因为这样是$sum frac{n}{i}$是调和级数,而它是发散的,所以复杂度并不大。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    int N,a[1000010],n[1000010],sn[1000010],maxx;
    LL ans,sum;
    int main()
    {
        scanf("%d",&N);
        for (int i=1; i<=N; i++) scanf("%d",&a[i]),n[a[i]]++,maxx=max(maxx,a[i]);
        for (int i=maxx; i; i--) sn[i]=sn[i+1]+n[i];
        for (int i=1,j=i; i<=maxx; i++,j=i)
            for (ans=max(ans,sum),sum=0; n[i] && j<=maxx; j+=i)
                sum+=(LL)j*(sn[j]-sn[j+i]);
        ans=max(ans,sum);
        printf("%I64d
    ",ans);
        return 0;
    }
    731F

    Codeforces148E

    题目大意:有N行数,每次可以从某行的开头或结尾去掉一个数,并得到这个数的价值,问最多取M次的最大价值和是多少。

    题解:背包DP,先一遍DP预处理出$f[i][j]$表示第i行取j个数的最大价值和,再利用$f[i][j]$进行DP求出$g[i][j]$表示前i行取j个数的最大价值和。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    inline 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;
    }
    #define size(i) s[i].size()-1
    vector<int>s[110],sum[110];
    int f[110][10010],g[110][10010],N,M;
    int main()
    {
        for (int i=1; i<=100; i++) s[i].push_back(0),sum[i].push_back(0);
        N=read(),M=read();
        for (int x,i=1,len,j; i<=N; i++) 
            for (len=read(),j=1; j<=len; j++)
                x=read(),s[i].push_back(x),sum[i].push_back(sum[i][j-1]+s[i][j]);
        for (int i=1; i<=N; i++)
            for (int j=1; j<=size(i); j++)
                for (int k=1; k+size(i)-j-1<=size(i); k++)
                    f[i][j]=max(f[i][j],sum[i][size(i)]-(sum[i][k+size(i)-j-1]-sum[i][k-1]));
    //    for (int i=1; i<=N; i++,puts(""))
    //        for (int j=1; j<=size(i); j++)
    //            printf("%d  ",f[i][j]);
        for (int i=1,j,len=0; i<=N; i++)
            for (len+=size(i),j=1; j<=len; j++)
                for (int k=0; k<=size(i); k++)
                    if (j>=k && len-(size(i))>=j-k)
                        g[i][j]=max(g[i][j],g[i-1][j-k]+f[i][k]);
    //    for (int i=1; i<=N; i++,puts(""))
    //        for (int j=1; j<=size(i); j++)
    //            printf("%d  ",g[i][j]);
        printf("%d
    ",g[N][M]);
        return 0;
    }
    148E

    Codeforces285E

    题目大意:求出满足good position的个数恰好为K个的全排列的个数  good position定义是$|a_{i}-i|=1$

    题解:这类题显然可以DP+容斥。$dp[i][j][k][l]$表示前i个已经放了j个gp,k表示i是否被放过,l表示i+1是否被放过,这样就可以转移。 最后统计答案,注意$ans[j]$出现在$ans[i]$中的次数是$C[j][i]$次。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define LL long long
    inline 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 N,K;
    LL ans[1010],f[1010][1010][2][2],fac[1010],C[1010][1010];
    #define P 1000000007
    int main()
    {
        fac[0]=1;     for (int i=1; i<=1000; i++) fac[i]=fac[i-1]*i%P;
        N=read(),K=read();
        C[0][0]=1; for (int j,i=1; i<=N; i++) for (C[i][0]=1,j=1; j<=i; j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
        f[0][0][1][0]=1;
        for (int i=1; i<=N; i++)
            for (int j=0; j<=N-1; j++)
                for (int k=0; k<=1; k++)
                    for (int l=0; l<=1; l++)
                        (f[i][j+1][l][0]+=(!k)? f[i-1][j][k][l]:0)%=P,
                        (f[i][j+1][l][1]+=(i!=N)? f[i-1][j][k][l]:0)%=P,
                        (f[i][j][l][0]+=f[i-1][j][k][l])%=P;
        for (int i=0; i<=N; i++)
            for (int j=0; j<=1; j++)
                for (int k=0; k<=1; k++)
                    (ans[i]+=f[N][i][j][k])%=P;
        for (int i=0; i<=N; i++) (ans[i]*=fac[N-i])%=P;
        for (int i=N; i>=0; i--)
            for (int j=i+1; j<=N; j++) ans[i]=(ans[i]-ans[j]*C[j][i])%P,ans[i]+=(ans[i]<0)? P:0;
        printf("%I64d
    ",ans[K]);    
        return 0;
    }
    285E

    Codeforces148D

    题目大意:一个袋子中一共有w个白球,b个黑球,公主和龙依次取一个球,取到率先白球的人获胜,每次龙取球,总会额外随机掉出一个球,求公主获胜的概率。

    题解:显然概率DP,而且很好转移,$dp[i][j]$表示现在还剩i个白球,j个黑球的时公主先手的获胜概率,那么分情况讨论即可,转移可以看代码。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    double f[1010][1010];
    int W,B;
    int main()
    {
        for (int i=1; i<=1000; i++) f[i][0]=1,f[0][i]=0;
        for (int i=1; i<=1000; i++)
            for (int j=1; j<=1000; j++)
                    f[i][j]+=(double)i/(i+j),
                    f[i][j]+=(j>=3)? ((double)j/(i+j))*((double)(j-1)/(i+j-1))*((double)(j-2)/(i+j-2))*((double)f[i][j-3]) : 0.0,
                    f[i][j]+=(j>=2 && i>=1)? ((double)j/(i+j))*((double)(j-1)/(i+j-1))*((double)i/(i-1+j-1))*((double)f[i-1][j-2]) : 0.0;
        while (scanf("%d%d",&W,&B)!=EOF) printf("%.9lf
    ",f[W][B]);
        return 0;
    }
    148D

    Codeforces268D

    题目大意:一共有N层,每层有4个方向可以爬,一次最多爬高度H,从底部爬到至少N-H+1~N的高度的方案数。

    题解:自己只会$O(NH^4)$的方法,就是$dp[i][n][e][s][w]$表示当前在第i层,北东南西四个方向分别距离为n/e/s/w的方案数,这样还需要滚动掉第i维。

    正解也是如此,不过有很巧妙的优化,因为每一层的操作总会存在一个距离为0的转移,所以就可以压掉一维状态,这样复杂度就是$O(NH^{3})$,这种优化或者可以理解为把这些状态旋转的记录下来,可以类比旋梯。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    #define P 1000000009
    int N,H;
    LL f[2][31][31][31][31],ans;
    #define dpn(now,nor,eas,sou,wes) f[now&1][nor<H? 0:H][eas+(eas<H)][sou+(sou<H)][wes+(wes<H)]
    #define dpe(now,nor,eas,sou,wes) f[now&1][nor+(nor<H)][eas<H? 0:H][sou+(sou<H)][wes+(wes<H)]
    #define dps(now,nor,eas,sou,wes) f[now&1][nor+(nor<H)][eas+(eas<H)][sou<H? 0:H][wes+(wes<H)]
    #define dpw(now,nor,eas,sou,wes) f[now&1][nor+(nor<H)][eas+(eas<H)][sou+(sou<H)][wes<H? 0:H]
    int main()
    {
        scanf("%d%d",&N,&H);
        f[0][0][0][0][0]=1;
        for (int i=1; i<=N; i++,memset(f[i&1],0,sizeof(f[i&1])))
            for (int nor=0; nor<=H; nor++)
                for (int eas=0; eas<=H; eas++)
                    for (int sou=0; sou<=H; sou++)
                        for (int wes=0; wes<=H; wes++)
                            (dpn(i,nor,eas,sou,wes)+=f[(i-1)&1][nor][eas][sou][wes])%=P,
                            (dpe(i,nor,eas,sou,wes)+=f[(i-1)&1][nor][eas][sou][wes])%=P,
                            (dps(i,nor,eas,sou,wes)+=f[(i-1)&1][nor][eas][sou][wes])%=P,
                            (dpw(i,nor,eas,sou,wes)+=f[(i-1)&1][nor][eas][sou][wes])%=P;
        for (int nor=0; nor<=H; nor++)
            for (int eas=0; eas<=H; eas++)
                for (int sou=0; sou<=H; sou++)
                    for (int wes=0; wes<=H; wes++)
                        (ans+=f[N&1][nor][eas][sou][wes])%=P;
        ans=(ans-f[N&1][H][H][H][H]+P)%P;    
        printf("%I64d
    ",ans);
        return 0;
    }
    268D未优化
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    #define P 1000000009
    int N,H;
    LL f[2][2][31][31][31],ans;
    int main()
    {
        scanf("%d%d",&N,&H);
        f[0][0][0][0][0]=1;
        for (int i=1; i<=N; i++,memset(f[i&1],0,sizeof(f[i&1])))
            for (int a=0; a<=1; a++)
                for (int b=0; b<=H; b++)
                    for (int c=0; c<=H; c++)
                        for (int d=0; d<=H; d++)
                            (f[i&1][!(a<1)][b+(b<H)][c+(c<H)][d+(d<H)]+=f[(i-1)&1][a][b][c][d])%=P,
                            (f[i&1][!(b<H)][c+(c<H)][d+(d<H)][a<1? 1:H]+=f[(i-1)&1][a][b][c][d])%=P,
                            (f[i&1][!(c<H)][d+(d<H)][a<1? 1:H][b+(b<H)]+=f[(i-1)&1][a][b][c][d])%=P,
                            (f[i&1][!(d<H)][a<1? 1:H][b+(b<H)][c+(c<H)]+=f[(i-1)&1][a][b][c][d])%=P;
        for (int a=0; a<=1; a++)
            for (int b=0; b<=H; b++)
                for (int c=0; c<=H; c++)
                    for (int d=0; d<=H; d++)
                        (ans+=f[N&1][a][b][c][d])%=P;
        ans=(ans-f[N&1][1][H][H][H]+P)%P;
        printf("%I64d
    ",ans);
        return 0;
    }
    268D优化

    Codeforces697D

    题目大意:模拟求树的DFS序的过程,要求求出每个节点的DFS序的期望,以1号为根。

    题解:树形DP,一个节点的DFS序编号为它前面的被遍历到的点的数目,所以可以考虑统计出每个节点的子树size,然后可以得到dp方程$f[v]=f[u]+1+frac{size[u]-size[v]-1}{2}$,然后就可以得到了。这种题必须要手画数据才能得到!!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline 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;
    }
    #define MAXN 100010
    int N;
    struct EdgeNode{int next,to;}edge[MAXN<<1];
    int head[MAXN],cnt=1,size[MAXN];
    inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    double f[MAXN];
    void DFS_1(int now,int last)
    {
        size[now]=1;
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=last)
                DFS_1(edge[i].to,now),size[now]+=size[edge[i].to];
    }
    void DFS_2(int now,int last)
    {
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=last)
                f[edge[i].to]=f[now]+1+(double)(size[now]-size[edge[i].to]-1)/2,DFS_2(edge[i].to,now);
    }
    int main()
    {
        N=read();
        for (int x,i=2; i<=N; i++) x=read(),InsertEdge(x,i);
        DFS_1(1,0); f[1]=1; DFS_2(1,0);
        for (int i=1; i<=N; i++) printf("%.1lf ",f[i]);
        return 0;
    } 
    697D
  • 相关阅读:
    git错误操作导致代码丢失找回
    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)问题
    WebMvcConfigurerAdapter在Spring boot2.x已废弃
    AJAX实现模拟注册跳转
    遍历字符串替换实例
    spring boot2.x依赖
    Thymeleaf页面添加th:value后报错原因
    thymeleaf中th:href字符拼接
    刁肥宅数据结构课设“布隆过滤器的实现和应用”源代码(v1.0,永不上交)
    数据结构实验1:C++实现静态顺序表类
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5975139.html
Copyright © 2020-2023  润新知