abc214 F - Substrings

题意:

求给定字符串 \(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; //空串不算
}
posted @ 2023-01-24 10:21  Bellala  阅读(22)  评论(0)    收藏  举报