P7888 「MCOI-06」Distinct Subsequences
总觉得就我一个人没有把问题转换成贡献
设
为了方便理解,我们把每一个 子序列 看作一个集合,(为了方便之后表述,我们定义这个集合的 集合名 为这个子序列)。
集合里的元素是它 本质不同的非空子序列 ,则这个集合的价值就是它的大小,
对于
其次,对于
容易想到,对于上一段所述的每一个集合,可以在其中每一个元素之后添加字符
但是有两个问题需要考虑。
首先,对于一个集合,如果它的集合名第一次加入
假如在
另外,在元素后添加
我们“退一步”想,假设这个发生冲突的集合是
如果在 虽然不清楚有没有这种运算)。
容易知道,要么这个子序列为空,要么这个子序列也同样存在于这个集合中。
那么我们可以认为在
(类似于,“此位置已存在名为 s1 且扩展名为 p 的项目。您要用正在移动的项目来替换它吗?“)
也就是说,发生冲突的元素个数就等于
对于
(
综上,
后面那个和式,可以通过对每个字符分别记录一个
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const long long mod = 1000000007;
inline int read() {
register int x = 0, f = 1; register char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48; ch = getchar();}
return x * f;
}
template<class T>inline T mmin(register T x, register T y) {
return x > y ? y : x;
}
template<class T>inline T mmax(register T x, register T y) {
return x > y ? x : y;
}
int n;
long long dp[1000007];
int lst[37], cnt[37];
long long del[37];
char ch[1000007];
inline long long power(long long a, long long b) {
long long ret = 1ll;
for(; b; b >>= 1) {
if(b & 1) ret = ret * a % mod;
a = a * a % mod;
}
return ret;
}
signed main() {
scanf("%s", ch + 1);
n = strlen(ch + 1);
dp[1] = 1; cnt[ch[1] - 'a'] = 1;
for(int i = 2; i <= n; ++i) {
int x = ch[i] - 'a';
dp[i] = dp[i - 1] * 3 % mod;
dp[i] = (dp[i] - del[x] % mod + mod) % mod;
dp[i] = (dp[i] + power(2, i - cnt[x] - 1)) % mod;
//这里的快速幂是可以避免的,但是这样写方便点(反正不会T
for(int j = 0; j < 26; ++j) if(j != x) del[j] = del[j] * 2 % mod;
del[x] = (del[x] + dp[i - 1]) % mod;
++cnt[x];
}
printf("%lld\n", dp[n]);
return 0;
}