题目链接:这里
题意:现在给你n,k和长度为m的串。你需要构造一个长度为n+m的串,使得其中不同的子序列最多,输出数量。
解法:贪心, dp, 构造。
首先先看给定的字符串t,要解决的第一个问题是要如何求字符串t中不相同的子串数量。
这一步可以dp来做,用dp[i]表示位置i之前的子串数量,假设当前已经考虑到了第i个位置,也就是说之前的dp[0]~dp[i-1]已经求了出来,
再用pos[j]表示字符j上次出现的位置
对于当前位置i来说,因为比上一次多了一个字符,所以会增加dp[I-1]个以当前字符结尾的新子串,但是这些子串中有重复的,也就是以当前字符上次位置作为结束位置的子串数量。
所以可以得到转移方程dp[I] = dp[I-1] * 2 - dp[ pos[t[I] - 1] ];
接下来是后面那部分怎么办?
//CF 655E
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000010;
const int mod = 1e9+7;
long long dp[maxn];
int pos[30];
char t[maxn];
int n, k;
int main(){
scanf("%d%d%s", &n, &k, t+1);
int len = strlen(t+1);
dp[0] = 1;
for(int i = 1; i <= len; i++){
dp[i] = (dp[i-1])*2;
if(pos[t[i]-'a']>0) dp[i] -= dp[pos[t[i]-'a'] - 1];
dp[i] %= mod;
pos[t[i]-'a'] = i;
}
for(int i = len+1; i <= len+n; i++){
dp[i] = dp[i-1]*2;
int id, p = i;
for(int j = 0; j < k; j++){
if(pos[j] < p){
p = pos[j];
id = j;
}
}
if(p > 0) dp[i] -= dp[p-1];
dp[i] %= mod;
pos[id] = i;
}
printf("%d\n", (dp[len+n]%mod+mod)%mod);
return 0;
}