题意:
求给定字符串 \(s\) 的不同非空子序列个数
要求被选入的位置两两不相邻
\(n\le 2e5\)
思路:
如果没有不相邻的要求怎么做?
\(f_i\) 表示考虑 \(s[1..i]\),并且选 \(i\) 位置的答案
\(f_i=\sum\limits_{j<i}f_j\) 显然会重复计数,怎么办?
只需要从每个字符的最后出现位置转移:\(f_i=\sum\limits_{c='a'}^{'z'} f_{las(c)}\),其中 \(las(c)\) 为字符 \(c\) 的最后出现位置
这是因为,若 \(i<j,s_i=s_j\),那么 \(f_j\) 表示的方案集包含 \(f_i\) 表示的方案集!
复杂度 \(O(26n)\),\(26\) 为字符集大小。可以通过神秘的前缀和技术优化到 \(O(n)\)
要求不相邻的话,只需改成 \(f_{i+1}=\sum\limits_{c='a'}^{'z'} f_{las(c)}\)
const int N = 2e5 + 5, P = 1e9 + 7;
ll n, g[27], sum, f[N], ans;
char s[N];
void sol() {
cin >> (s + 1); n = strlen(s + 1);
s[0] = s[n + 1] = 'a' + 26;
f[0] = g[26] = sum = 1; //神秘初值
for(int i = 0; i <= n; i++) {
f[i + 1] = sum;
sum = (sum - g[s[i] - 'a'] + f[i]) % P;
g[s[i] - 'a'] = f[i];
}
cout << (sum - 1 + P) % P; //空串不算
}
标签:26,limits,abc214,int,sum,Substrings,las
From: https://www.cnblogs.com/wushansinger/p/17065899.html