题面
解析
需要先来一手概率生成函数。
定义概率生成函数$f(x)=sum_{i=0}^{infty}P(Y==i)x^i$,其中$P(Y==i)$表示$Y$这个变量取$i$的概率,容易发现$f(1) = 1$
对该概率生成函数求导:$f'(x)=sum_{i=1}^{infty}P(Y==i)i*x^{i-1}$,那么可以发现$f'(1)$即是$Y$的期望
接下来开始解决这道题。
设$f_i$表示终止长度为$i$的概率,$F(x)$为其生成函数。设$g_i$表示长度为$i$还未终止的概率,$g_0=1$,$G(x)$为其生成函数。
考虑$g_i$向$f_{i+1}$与$g_{i+1}$转移,即在长度为$i$的未终止的串后加一个字符:$g_i=f_{i+1}+g_{i+1}$,也即:$$F(x)+G(x)=x*G(x)+1$$
因为$F'(1)$为所求,因此两边求导:$$F'(x)+G'(x)=x*G'(x)+G(x)$$
代入$x=1$:$$F'(1)=G(1)$$
现在只要求出$G(1)$即可
设目标串串长为$m$,字符集大小为$n$,$a_i=1/0$表示$[1,i]$是否为目标串的一个$border$
考虑在任意一个未终止串后加上一个目标串都一定可以终止,但可能在加到中间某个字符时就可以终止了,所以枚举真正所需要的串的长度,有方程:$g_i(frac{1}{n})^m=sum_{j=1}^{m}a_jf_{i+j}(frac{1}{n})^{m-j}$,即:$$G(x)(frac{1}{n})^m*x^m=F(x)sum_{i=1}^{m}a_i(frac{1}{n})^{m-i}*x^{m-i}$$
代入$x=1$:$$G(1)=sum_{i=1}^m a_i*n^i$$
$KMP$求出$a$数组即可
$O(N)$
代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn = 100005, mod = 10000; inline int read() { int ret, f=1; char c; while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1; ret=c-'0'; while((c=getchar())&&(c>='0'&&c<='9'))ret=(ret<<3)+(ret<<1)+c-'0'; return ret*f; } int add(int x, int y) { return x + y < mod? x + y: x + y - mod; } int n, m, T, a[maxn], fail[maxn], pw[maxn]; void KMP() { int t; for(int i = 2; i <= m; ++i) { t = fail[i-1]; while(t && a[t+1] != a[i]) t = fail[t]; fail[i] = ((a[t+1] == a[i])? t + 1: 0); } } int main() { n = read(); T = read(); pw[0] = 1; for(int i = 1; i <= 100000; ++i) pw[i] = pw[i-1] * n % mod; int ans; while(T --) { m = read(); for(int i = 1; i <= m; ++i) a[i] = read(); KMP(); ans = 0; for(int i = m; i; i = fail[i]) ans = add(ans, pw[i]); printf("%d%d%d%d ", ans / 1000, (ans / 100) % 10, (ans / 10) % 10, ans % 10); } return 0; }