L3-020 至多删三个字符 [DP]

这题在网上看到一个非常容易理解的思路,和大家分享一下。

记dp[i][j]为前i个字符删除j个字符后得到不同字符串的数量,可以得到以下两个转移方程

dp[i][j+1]=dp[i][j+1]+dp[i-1][j] (删除s[i])

dp[i][j]=dp[i][j]+dp[i-1][j] (不删除s[i])

 如果只用上述式子,是会重复的。比如abcdecf,删除cde得到abcf,删除dec得到的也是abcf。

所以要删除重复计算的。从当前的i向左扫,扫到的第一个与s[i]相同的字符时处理,假设为s[k],那么dp[i][j]=dp[i][j]-dp[k-1][j-(i-k)]。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#define maxn 1000005
using namespace std;
typedef long long ll;
char s[maxn];
ll dp[maxn][5];
int main()
{
    scanf("%s",s+1);
    int l=strlen(s+1);
    dp[0][0]=1;
    for(int i=0;i<=l;i++)
    {
        for(int j=0;j<=3;j++)
        {
            if(dp[i-1][j]==0)
                continue;
            if(j<3)
                dp[i][j+1]+=dp[i-1][j];
            dp[i][j]+=dp[i-1][j];
            for(int k=i-1;k>=1&&i-k<=j;k--)
            {
                if(s[k]==s[i])
                {
                    dp[i][j]-=dp[k-1][j-i+k];
                    break;//如果有多个,因为是从前往后推的,所以在前面减过了
                }
            }
        }
    }
    printf("%lld\n",dp[l][0]+dp[l][1]+dp[l][2]+dp[l][3]);
    return 0;
}
View Code

 

posted on 2019-03-04 20:05  FTA_Macro  阅读(563)  评论(0编辑  收藏  举报

导航