zoukankan      html  css  js  c++  java
  • codeforces 792CDivide by Three(两种方法:模拟、动态规划

    传送门:https://codeforces.com/problemset/problem/792/C

    题意:给你一个字符串,要求让你删除最少个数的元素,使得最终答案是没有前导0并且是3的倍数。

    题解:模拟:既然是3的倍数,那么第一步肯定是将每个都模上3,讨论长度为1的特殊情况,然后,我们讨论数字模上 3后的和sum

        如果sum为0 直接输出,

        如果sum为1,我们就要删去一个mod3为1的数或者两个mod3为2的数      

        如果sum为2,我们就要删去一个mod3为2的数或者两个mod3为1的数

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    char s[100010];
    int a[3];
    int t,flag,n,p;
    int main(){
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++){
            t=(t+s[i])%3;
            a[s[i]%3]++;
        }
        //相加和为0直接输出
        if(!t){
            puts(s+1);
            return 0;
        }
        for(p=2;s[p]=='0';p++);
            p-=2;
    
        if(a[t]&&n>1&&(p<=1||a[t]>1||s[1]%3!=t)) 
            a[t]--;
        else if(a[3-t]>1&&n>2) 
            a[3-t]-=2;
        else if(a[t]&&n>1) 
            a[t]--;
        else {
            puts("-1");
            return 0;
        }
        /*
          t==1,那么我们可以删去一个模3等于1的数字位,
            或者删去两个模3等于2的数字位(这个很容易漏)。
            */
        /*
          t==2,可以删去一个模3等于2的数字位,
            或者删去两个模3等于1的数字位。
            */
        for(int i=1;i<=n;i++){
            if(s[i]=='0'&&!flag) continue;
            if(a[s[i]%3]) {
                putchar(s[i]);
                a[s[i]%3]--;
                flag=1;
            } 
        }
        if(!flag) puts("0");
    }
    View Code

       动态规划:

        设定dp[i][3]=x表示:

      1.dp[i][0]:[0~i]中剩余的数字每个位子相加模3为0的删除最少元素的个数。

      2.dp[i][1]:[0~i]中剩余的数字每个位子相加模3为1的删除最少元素的个数。

      3.dp[i][2]:[0~i]中剩余的数字每个位子相加模3为2的删除最少元素的个数。

      dp[i][j]=min(dp[i][j],dp[i-1][((j-a[i]%3)%3+3)%3)];

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 3;
    const int maxn = 1e5+5;
    const int INF = 0x3f3f3f3f;
    int dp[maxn][3];
    int pre[maxn][3];
    char str[maxn];
    char ans[maxn];
    int main(){
        while(cin>>str){
            int n=strlen(str);
            if(n==1){
                if((str[0]-'0')%3==0) printf("%c
    ",str[0]);
                else printf("-1
    ");
                continue;
            }
            memset(pre,-1,sizeof(pre));
            memset(dp,INF,sizeof(dp));
            dp[0][0]=1;
            dp[0][(str[0]-'0')%3]=0;
            for(int i=1;i<n;i++){
                for(int j=0;j<3;j++){
                    if(dp[i-1][j]+1<dp[i][j]){
                        dp[i][j]=dp[i-1][j]+1;
                        pre[i][j]=j;
                    }
                    if((str[i]-'0')%3==0){
                        if(str[i]=='0'){
                            if(dp[i-1][j]!=i&&dp[i-1][j]<dp[i][j]){
                                dp[i][j]=dp[i-1][j];
                                pre[i][j]=j;
                            }
                        }else{
                            if(dp[i-1][j]<dp[i][j]){
                                dp[i][j]=dp[i-1][j];
                                pre[i][j]=j;
                            }
                        }
                    }
                    if((str[i]-'0')%3==1&&dp[i-1][((j-1)%mod+mod)%mod]<dp[i][j]){
                        dp[i][j]=dp[i-1][((j-1)%mod+mod)%mod];
                        pre[i][j]=((j-1)%mod+mod)%mod;
                    }
                    if((str[i]-'0')%3==2&&dp[i-1][((j-2)%mod+mod)%mod]<dp[i][j]){
                        dp[i][j]=dp[i-1][((j-2)%mod+mod)%mod];
                        pre[i][j]=((j-2)%mod+mod)%mod;
                    }
                }
            }
            if(dp[n-1][0]==n){
                int flag=0;
                for(int i=0;i<n;i++){
                    if(str[i]=='0') flag=1;
                } 
                if(flag==1) printf("0
    ");
                else printf("-1
    ");
                continue;
            }
            int cnt=0;
            int now=n-1;
            int j=0;
            while(now>=1){
                int pree=pre[now][j];
                if(dp[now-1][pree]==dp[now][j]){
                    ans[cnt++]=str[now];
                }
                j=pree;
                now--;
                if(now==0){
                    if(pree==(str[0]-'0')%3){
                        ans[cnt++]=str[now];
                    }
                }
            }
            for(int i=cnt-1;i>=0;i--){
                printf("%c",ans[i]);
            }
            printf("
    ");
        }
    }
    View Code
    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    「Luogu2397」 yyy loves Maths VI (mode)
    「Luogu2014」 选课
    「Luogu2972」 [USACO10HOL]岩石和树木Rocks and Trees
    中国剩余定理
    点双连通分量
    Miller_Rabin大质数检验
    manachaer算法
    Kruskal重构树
    世界,你好!
    [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/9526284.html
Copyright © 2011-2022 走看看