给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?
输入格式:
输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 1] 内的字符串。
输出格式:
在一行中输出至多删掉其中 3 个字符后不同字符串的个数。
输入样例:
ababcc
输出样例:
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"。
作者: 曹鹏
单位: Google
时间限制: 400 ms
内存限制: 64 MB
数据到了106 很明显用dp来做
dp[i][j]表示 前i个字符 删除j个字符的 种类
1基础的状态转移
也就是拆与不拆:
dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
2判重
有些重复的加了多次 要减回去
例如一个字符串cd abna xy,你删除abn和删除bna后得到的字符串都是cdaxy。(这个区间长度为3)
这时候就要去重了,根据上面那个例子可以发现对于一个字符s[i],如果在i之前存在一个x使得s[x]=s[i],那么删除[x,i-1]间的字符 和删除[x+1,i]间的字符其实是重复的,等价的,那么d[i][j]就要减去d[x-1][j-(i-x)],减去删除这段造成的重复串。
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);i--) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define LL long long #define pb push_back #define fi first #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) /////////////////////////////////// #define inf 0x3f3f3f3f #define N 10000000+5 LL dp[N][4]; char s[N]; int pos[N]; int main() { RS(s+1); int len=strlen(s+1); dp[0][0]=1; rep(i,1,len) { dp[i][0]=1; int ch=s[i]-'a'; int d=pos[ch]; pos[ch]=i; rep(j,1,3) { dp[i][j]+=dp[i-1][j]+dp[i-1][j-1]; if(d&&j-i+d>=0) dp[i][j]-=dp[d-1][j-i+d]; } } printf("%lld",dp[len][0]+dp[len][1]+dp[len][2]+dp[len][3] ); return 0; }