codeforces 792CDivide by Three(两种方法:模拟动态规划

Posted buerdepepeqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于codeforces 792CDivide by Three(两种方法:模拟动态规划的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 792C. Divide by Three

CodeForce-792C Divide by Three(数学)

CodeForces 792C - Divide by Three [ 分类讨论 ]

Codeforces 792C. Divide by Three 贪心+分类讨论

CodeForces - 792C

Codeforces Round #792 (Div. 1 + Div. 2)