pta2018 L3-2 至多删三个字符(30 分)

L3-2 至多删三个字符(30 分)

给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?

输入格式:

输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 10

6

] 内的字符串。

输出格式:

在一行中输出至多删掉其中 3 个字符后不同字符串的个数。

输入样例:

ababcc

输出样例:

扫描二维码关注公众号,回复: 139398 查看本文章

25

提示:

删掉 0 个字符得到 "ababcc"

删掉 1 个字符得到 "babcc", "aabcc", "abbcc", "abacc" "ababc"

删掉 2 个字符得到 "abcc", "bbcc", "bacc", "babc", "aacc", "aabc", "abbc", "abac" "abab"

删掉 3 个字符得到 "abc", "bcc", "acc", "bbc", "bac", "bab", "aac", "aab", "abb" "aba"



dp[i][j](i代表字符串长度,j代表删除的位数)


可推的dp[i][j]=dp[i-1][j-1]+dp[i-1][j]

因为增加的这一位要么被删除了,要么还保留着



现在得到的是一般字符串的递推公式,比如abcde

还有比较特殊的要处理,比如abab,aaaaa等

那么需要一些特判条件来满足



如果出现了XX这样相邻的:

                   1.那么dp[i][1]=dp[i-1][1](删一位的数量没变)

                  2.那么删两位的数量要比正常的减少dp[i-2][1];因为删第一个X和删第二                        个X重复,所以要减去一个dp[i-2][1](前面i-2个中有一个被删)

                  3.那么删三位的数量要比正常的减少dp[i-2][2];因为删第一个X和删第                        个X重复,所以要减去一个dp[i-2][2](前面i-2个中有两个被删)



如果出现了X_X这样相邻的:(注意,不包括XXX这种情况)

                        1.删一位不用处理,与一般相同

                   2.删两位只会在删X_和删_X时相同,所以减1即可

                    3.删三位其实就是删_X_和删_ _X时重复,所以减去dp[i-3][1]即可



如果出现了X_X这样相邻的:(注意,不包括XXXX,XX_X,X_XX这几种情况)

                    

                      1.删一位不用处理,与一般的相同

                       2.删两位不用处理,与一般的相同

                        3.删三位其实就是删X_ _和删_ _X时重复,所以减去1即可


#include<iostream>
using namespace std;
long long dp[1000005][4];
int main(){
    string ss;
    cin>>ss;
    dp[1][0]=dp[1][1]=1;
    dp[0][2]=dp[0][3]=0;
    int n=int(ss.size());
    for(int i=2;i<=n;i++){
        dp[i][0]=1;
        for(int j=1;j<=3;j++){
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
            if(ss[i-1]==ss[i-2]&&j==1) dp[i][j]-=1;
            else if(ss[i-1]==ss[i-2]&&j==2) dp[i][j]-=dp[i-2][1];
            else if(ss[i-1]==ss[i-2]&&j==3) dp[i][j]-=dp[i-2][2];
            
            if(i>=3&&ss[i-1]==ss[i-3]&&ss[i-1]!=ss[i-2]&&j==2) dp[i][j]-=1;
            else if(i>=3&&ss[i-1]==ss[i-3]&&ss[i-1]!=ss[i-2]&&j==3) dp[i][j]-=dp[i-3][1];
            
            if(i>=4&&ss[i-1]==ss[i-4]&&ss[i-1]!=ss[i-2]&&ss[i-1]!=ss[i-3]&&j==3) dp[i][j]-=1;
            
           //printf("%lld ",dp[i][j]);
        }
        //printf("\n");
    }
    cout<<dp[n][0]+dp[n][1]+dp[n][2]+dp[n][3]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/aaakirito/article/details/80015126