题解:P4548 [CTSC2006] 歌唱王国
这是一道神秘的生成函数题,我们首先挖掘概率生成函数的一些性质,其中 \(P(X)\) 表示 \(X\) 事件的概率,\(E(x)\) 表示期望,\(A'\) 是 \(A\) 的导数:
\[A(x)=\sum_{i=0}^\infty P(X=i)x^i
\]
\[A'(x)=\sum_{i=0}^\infty iP(X=i)x^{i-1}
\]
考虑带入 \(x=1\),则 \(A(1)=1,A'(x)=E(X)\)。
正文
考虑设 \(F(x)\) 的 \(i\) 次项表示 \(i\) 次后游戏恰好结束的概率,\(G(x)\) 表示游戏未结束的概率(\(G\) 并不适用上述性质,因为其每个项的系数相当于一个后缀和)。则根据其意义有:
\[F(x)+G(x)=xG(x)+1
\]
这是因为无论第 \(i+1\) 次是否结束,第 \(i\) 次定然没有结束,\(+1\) 是为了补齐常数项。对这个式子两边求导有:
\[F'(x)+G'(x)=xG'(x)+G(x)
\]
代入 \(x=1\),再根据开头分析的性质,有:
\[F'(1)+G'(x)=G'(x)+G(1)
\]
\[E(X)=F'(1)=G(1)
\]
因此我们求解 \(G(1)\) 即可,而我们有 \(F(1)=1\),所以我们要把 \(G(x)\) 用 \(F(x)\) 表示。因此我们需要使得游戏在 \(G(x)\) 之后必须结束,可以在后面拼一个原串,如果设 \(b_i\) 表示 \([1,i]\) 是不是一个 border(原串也被认为是一个 border),原串的长度为 \(n\),字符集的大小为 \(m\),则有:
\[G(x)(\frac1mx)^n = \sum_{i = 1}^nb_iF(x)(\frac1mx)^{n-i}
\]
这是因为拼一个原串后可能会提前结束,而结束的位置一定是原串的一个 border。接下来我们把两边同乘 \(m^n\),则有:
\[G(x)x^n=\sum_{i=1}^nb_iF(x)x^{n-i}m^i
\]
代入 \(x=1\) 有:
\[G(1)=\sum_{i=1}^nb_im^i
\]
KMP 求解即可,时间复杂度 \(O(\sum n)\)。
参考资料:题解 P3706 【[SDOI2017]硬币游戏】
Code:
#include<iostream>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=1e5+5,mod=1e4;
int s[maxn],nxt[maxn],pw[maxn],o[10];
int main(){
int in,it;
cin>>in>>it;
pw[0]=1;
rep(v1,1,1e5)pw[v1]=pw[v1-1]*in%mod;
while(it--){
int im;
scanf("%d",&im);
rep(v1,1,im)scanf("%d",s+v1);
int cp=0;
rep(v1,2,im){
while(cp&&s[cp+1]!=s[v1])cp=nxt[cp];
if(s[cp+1]==s[v1])cp++;
nxt[v1]=cp;
}
int p=im,ans=0;
while(p){
ans=(ans+pw[p])%mod;
p=nxt[p];
}
rep(v1,1,4){
o[v1]=ans%10;
ans/=10;
}
per(v1,4,1)printf("%d",o[v1]);
printf("\n");
}
return 0;
}

浙公网安备 33010602011771号