至多删三个字符(dp 字符串)

原题: https://pintia.cn/problem-sets/994805046380707840/problems/994805046946938880

题意:

给出一个字符串,可以删除0~3个字符,问结果的可能种数。

解析:

很自然的想法,用 d p [ i ] [ j ] dp[i][j] 表示到了第i个位置,删除j个字符的可能性。显然有 d p [ i ] [ j ] = d p [ i 1 ] [ j 1 ] + d p [ i ] [ j ] dp[i][j]=dp[i-1][j-1]+dp[i][j] 。但是会有重复的情况,例如,删除一个字符时 a a aa 会重复,删除两个时 a b a aba 会重复,三个时 a b c a abca 会重复。

其他情况都可以归结为这三种,例如 a a b b aabb 虽然删除第一个a和第二个b会重复,但是可以看成前面两个a与后面两个b造成的影响。

假设i前面最多j的位置k有一个字符与第i个字符相同,那么 d p [ i ] [ j ] dp[i][j] 相当于多算了 d p [ k 1 ] [ j ( i k ) ] dp[k-1][j-(i-k)]

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
char x[1000009];
long long dp[1000009][4];
int main(){
    scanf("%s",x+1);
    int len=strlen(x+1);
    for(int i=0;i<=len;i++)dp[i][0]=1;
    for(int i=1;i<=len;i++){
        for(int j=1;j<=min(3,i);j++){
            dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
            for(int k=i-1;i-k<=j&&k>0;k--){
                if(x[k]==x[i]){
                    dp[i][j]-=dp[k-1][j-(i-k)];
                    break;
                }
            }
        }
    }
    printf("%lld\n",dp[len][0]+dp[len][1]+dp[len][2]+dp[len][3]);
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88866561