题解 LGP7888【「MCOI-06」Distinct Subsequences】
problem
给定一个由小写字符构成的字符串 \(S\)。
令一个字符串的价值为该串的本质不同非空子序列个数,其中子序列可以为整体。
求 \(S\) 所有子序列的价值和。答案对 \(10^9+7\) 取模。
对于 \(100\%\) 的数据,\(1\le |S|\le 10^6\)。
solution
考虑如何求出一个字符串的价值?
令 \(f_i\) 表示以字符 \(i\) 为结尾有多少个本质不同的非空子序列。
增量法,每次加入字符 \(r\),将 \(f_r\) 修改为 \(1+\sum_{i}f_i\),表示将之前所有以 \(r\) 为结尾的子序列都接上 \(r\),最后补上单独的 \(r\)。
我们可以将这样的过程表示为矩阵:(假设只有 \(3\) 个字符,加入字符 \(1\))
\[\begin{bmatrix}
f_0 &f_1 &f_2 &1
\end{bmatrix}\times
\begin{bmatrix}
1 &1 &0 &0\\
0 &1 &0 &0\\
0 &1 &1 &0\\
0 &1 &0 &1
\end{bmatrix}=
\begin{bmatrix}
f'_0 &f'_1 &f'_2 &1
\end{bmatrix}.
\]
回到原问题,要求所有子序列的价值之和。我们考虑用二项式展开的集合意义:形如
\[(a_1+1)(a_2+1)(a_3+1)=1+a_3+a_2+a_2a_3+a_1+a_1a_3+a_1a_2+a_1a_2a_3.
\]
这样的东西可以求出所有子集的积的和。我们将 \(a_i\) 换成矩阵,\(1\) 换成单位矩阵,那么这个东西可以通过左式去算:
\[\begin{bmatrix}0 &0 &1\end{bmatrix}
\left(
\begin{bmatrix}1 &0 &0\\0 &1 &0\\0 &0 &1\\\end{bmatrix}+
\begin{bmatrix}1 &0 &0\\1 &1 &0\\1 &0 &1\\\end{bmatrix}
\right)
\left(
\begin{bmatrix}1 &0 &0\\0 &1 &0\\0 &0 &1\\\end{bmatrix}+
\begin{bmatrix}1 &1 &0\\0 &1 &0\\0 &1 &1\\\end{bmatrix}
\right).
\]
结果的和就是样例一的答案。
暴力是 \(O(n|\Sigma|^2)\) 的,但是我们发现这个矩阵只有 \(O(n)\) 个有效值,因此复杂度降为 \(O(n|\Sigma|)\),可以通过。
solution 2
强制数这样的子序列,满足 \(i,j\) 之间没有 \(S_j\),令 \(f_i\),则 \(f_i=\sum_j f_j\times 2^{i-j-cnt_{S_j}(i,j)}\)。
code
点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <numeric>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
const int P=1e9+7;
void red(LL&x){x=(x%P+P)%P;}
int n;
char buf[1000010];
vector<LL> append(vector<LL> f,int r){
LL sum=accumulate(f.begin(),f.end(),0ll)%P;
vector<LL> g(27);
for(int i=0;i<27;i++){
red(g[i]=f[i]);
if(i==r) red(g[i]=sum);
red(g[i]+=f[i]);
}
return g;
}
void print(vector<LL>&f){
// for(LL x:f) debug("%lld ",x);
// puts("");
}
int main(){
// #ifdef LOCAL
// freopen("input.in","r",stdin);
// #endif
scanf("%s",buf+1),n=strlen(buf+1);
vector<LL> f(27,0); f[26]=1;
for(int i=1;i<=n;i++) f=append(f,buf[i]-'a'),print(f);
printf("%lld\n",accumulate(f.begin(),prev(f.end()),0ll)%P);
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-P7888.html