题意:给定 n 个串,询问长度为m的串在这n个串中的贡献之和的期望。贡献的求法是 出现的所有串的val的乘积。
思路:首先要求输出分数,那我们分为分子和分母来考虑,分母很好求。对于分子来说,我们只需要算出长度小于等于m的所有串的贡献之和。 问题转化为 n个串中所有本质不同的子串的贡献,那么我们统计每个状态在那些串中出现过即可。
疑问:这题我一开始采用在线的做法,就是每加入一个字母就更新当前串的所有后缀,WA掉了。
然后我改成插入n个串以后一起更新,还有每插完一个串后做一遍更新,都能AC,到底是为什么。。。
还有广义后缀自动机到底是个啥啊。。。为什么出现过的节点重新建立也不会错啊。。。
原则:广义后缀自动机不在线更新。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 300005;
LL val[maxn<<1],vis[maxn<<1];
const int ch_size = 26;
const LL mod = 1000000007;
LL mpow( LL x,int y ){
LL res = 1;
while(y){
if( y&1 ) res = res*x%mod;
y >>= 1;
x = x*x%mod;
}
return res;
}
LL inv( LL x ){
return mpow( x,mod-2 );
}
struct SAM{
int fa[maxn<<1], // 后缀链接
ch[maxn<<1][ch_size],
len[maxn<<1], //该节点最长串的长度
tot, // 节点总数
last; // 代表当前的整个串
void init(){
tot = last = 0;
fa[0] = -1;
len[0] = 0;
memset( ch[0],0,sizeof( ch[0] ) );
}
void extend( int x ){
int p = last;
if( ch[p][x] ){
int q = ch[p][x];
if( len[q] == len[p]+1 ) last = q;
else{
int clone = ++tot;
len[clone] = len[p] + 1;
last = clone;
val[clone] = val[q];
for (int i = 0; i < ch_size; i++) {
ch[clone][i] = ch[q][i];
}
fa[clone] = fa[q];
fa[q] = clone;
while (p != -1) {
if (ch[p][x] == q)ch[p][x] = clone;
else break;
p = fa[p];
}
}
return;
}
int cur = ++tot;
memset( ch[cur],0,sizeof( ch[cur] ) );
len[cur] = len[last]+1;
while( p != -1 && !ch[p][x] ){
ch[p][x] = cur;
p = fa[p];
}
if( p == -1 ){
fa[cur] = 0;
}else {
int q = ch[p][x];
if (len[q] == len[p] + 1) {
fa[cur] = q;
} else {
int clone = ++tot;
len[clone] = len[p] + 1;
val[clone] = val[q];
for (int i = 0; i < ch_size; i++) {
ch[clone][i] = ch[q][i];
}
fa[clone] = fa[q];
fa[q] = fa[cur] = clone;
while (p != -1) {
if (ch[p][x] == q)ch[p][x] = clone;
else break;
p = fa[p];
}
}
}
last = cur;
}
}g;
void solve( int x,LL v,int flag ){
while(x){
vis[x] = flag;
val[x] = val[x] ? val[x]*v%mod : v;
x = g.fa[x];
if( vis[x]==flag )break;
}
}
LL val2[maxn<<1],vis2[maxn<<1];
char str[maxn];
vector<string> ve;
vector<int> ve2;
LL ans[1000005],mypow[1000005];
void build(){
for( int x = 1;x <= g.tot;x++ ) {
ans[g.len[g.fa[x]] + 1] = (ans[g.len[g.fa[x]] + 1] + val[x] + mod) % mod;
ans[g.len[x] + 1] = (ans[g.len[x] + 1] - val[x] + mod) % mod;
}
}
int main(){
int n,x;
scanf("%d",&n);
g.init();
for( int i = 1;i <= n;i++ ){
scanf("%s",str);
ve.push_back( string(str) );
}
for( int i = 1;i <= n;i++ ){
scanf("%d",&x);ve2.push_back(x);
}
int L=0;
for( int i = 0;i < ve.size();i++ ){
string str = ve[i];
int len = str.length(); L = max( L,len );
g.last = 0;
for( int j = 0;j < len;j++ ){
g.extend( str[j]-'a' );
}
}
for( int i = 0;i < ve.size();i++ ){
string str = ve[i];
int p = 0;
for( int j = 0;j < str.size();j++ ){
int c = str[j]-'a';
p = g.ch[p][c];
solve(p,ve2[i],i+1);
}
}
build();
for (int i=1;i<1000002;i++){
ans[i] = (ans[i-1]+ans[i])%mod;
}
for (int i=1;i<1000002;i++){
ans[i] = (ans[i]+ans[i-1])%mod;
}
mypow[0]=1;
for (int i=1;i<1000002;i++){
mypow[i] = 26LL*mypow[i-1]%mod;
}
for (int i=2;i<1000002;i++){
mypow[i] = (mypow[i]+mypow[i-1])%mod;
}
for (int i=1;i<1000002;i++){
ans[i] = 1LL*ans[i]*inv(mypow[i])%mod;
}
int q;
scanf("%d",&q);
while(q--){
int m;scanf("%d",&m);
printf("%lld\n", ans[m] );
}
return 0;
};