題意:一開始有一個字符串s,有m個事件,每一個事件形如:node
1.用一個新的字符串t來替換s
2.給出n,問有多少個長度爲n的小寫字母組成的字符串知足包含s做爲其一個子序列?答案$\mod 10^9+7$ios
$m,n,\sum |t|\le 10^5$spa
題解:有一個結論:答案只與n和|s|有關,與s究竟是什麼無關。咱們只考慮s在母串中第一次出現的位置。設$|s|=k$,假如s的每一個字符出現的位置分別是$p_1p_2...p_k$,則對於$i\in [1,k]$,$(p_{i-1},p_i)$之間的字符都不能是$s_i$,因此這些位置都有25種可能。而後咱們就能夠將咱們發現的結論形式化的寫出來了。咱們枚舉$p_k$的位置,則有:blog
$ans=\sum\limits_{i=k}^{n}C_{i-1}^{k-1}\alpha^{n-i}(\alpha-1)^{i-k}$事件
可是若是咱們每次都暴力計算的話複雜度難以接受。不過咱們發現本質不一樣的|s|只有$\sqrt n$種,因此咱們去重,而後將式子改寫爲:字符串
$ans=\alpha^{n}\sum\limits_{i=k}^nC_{i-1}^{k-1}\alpha^{-i}(\alpha-1)^{i-k}$get
咱們對於每一個|s|都預處理出後面那些東西,即可作到$O(1)$回答詢問,時間複雜度$O(m\sqrt n)$。string
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn=100010; const ll P=1000000007; int m,N,tot; struct node { int n,len,org; }p[maxn]; char str[maxn]; ll jc[maxn],ine[maxn],jcc[maxn],q[maxn],q1[maxn],qi[maxn],s[maxn],ans[maxn]; bool cmp(const node &a,const node &b) { return a.len<b.len; } inline ll c(int a,int b) { if(a<b) return 0; return jc[a]*jcc[a-b]%P*jcc[b]%P; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } int main() { m=rd(),scanf("%s",str),N=100000; int i,j,a=strlen(str),b; for(i=1;i<=m;i++) { if(rd()==1) scanf("%s",str),a=strlen(str); else b=rd(),p[++tot].len=a,p[tot].n=b,p[tot].org=tot; } ine[0]=ine[1]=jc[0]=jc[1]=jcc[0]=jcc[1]=1; for(i=2;i<=N;i++) jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P; for(q[0]=q1[0]=qi[0]=i=1;i<=N;i++) q[i]=q[i-1]*26%P,q1[i]=q1[i-1]*25%P,qi[i]=qi[i-1]*ine[26]%P; sort(p+1,p+tot+1,cmp); for(i=1;i<=tot;i++) { a=p[i].len,b=p[i].n; if(a!=p[i-1].len) { memset(s,0,sizeof(s[0])*a); for(j=a;j<=N;j++) s[j]=(s[j-1]+q1[j-a]*qi[j]%P*c(j-1,a-1))%P; } ans[p[i].org]=q[b]*s[b]%P; } for(i=1;i<=tot;i++) printf("%lld\n",ans[i]); return 0; }