L3-020 至多删三个字符 (30 分)
作者:互联网
给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?
输入格式:
输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 106] 内的字符串。
输出格式:
在一行中输出至多删掉其中 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"。
分析:设f[i][j]表示前i个字符中删除j个不同字符串的数量(下标从1开始),根据第i个字符的状态,很容易想到第i个字符删或不删有两种情况,所以f[i][j]=f[i-1][j]+f[i-1][j-1]。但是仅仅这样考虑会把一些相同的字符串状态重复计算,比如 abcded,在计算f[6][2]时删去‘de’或者删去‘ed’都会得到‘abcd’,造成了重复计算,重复计算的数量为f[3][0],也就是前3个字符一个都不删的情况。在计算f[6][3]时重复计算的数量为f[3][1],也就是前3个字符删掉一个的情况。这时需要设置一个标记pos记录当前字符上一次出现的位置,如果pos>0&&j-(i-pos)>=0,则f[i][j]-=f[pos-1][j-(i-pos)],j-(i-pos)表示它到位置pos-1删除了几个字符。
#include <iostream>
#include <cstring>
using namespace std;
char str[1000000+10];
int f[1000000+10][4],hashTable[26];
int main(){
scanf("%s",str+1);
int n=strlen(str+1);
for(int i=0;i<=n;i++) f[i][0]=1;
for(int i=1;i<=n;i++){
int pos=hashTable[str[i]-'a'];
hashTable[str[i]-'a']=i;
for(int j=1;j<=3;j++){
f[i][j]=f[i-1][j-1]+f[i-1][j];
if(pos&&j-(i-pos)>=0)
f[i][j]-=f[pos-1][j-(i-pos)];
}
}
printf("%d",f[n][0]+f[n][1]+f[n][2]+f[n][3]);
return 0;
}
标签:至多,30,int,删掉,pos,L3,字符串,个字符,020 来源: https://blog.csdn.net/qq_40597059/article/details/102679170