Luogu4548 歌唱王国
题面:Luogu
解析
很有趣的一道题目。
考虑一类生成函数,对于一个离散的整型随机变量(t),该函数的每一项(x^i)的系数表示该变量取值为(i)的概率,也就是:
[f(x)=sum_{i=0}^{infty} P(t=i)x^i
]
这个函数有一些有趣的性质,例如:(f(1)=1)
以及对于(t)的期望有:(E(t)=f'(1))
现在对于这道题目,令(n)表示字符集大小,(m)表示名字长度。
考虑设(F(x))表示对于在唱第(i)个数字结束的概率的生成函数,(G(x))表示对于在唱第(i)个数字未结束的概率的生成函数。
显然有下面这个式子:
[xG(x)+1=F(x)+G(x)
]
即在未结束的串后再接上一个字符,有可能结束,也可能不结束。
其次,有:
[G(x) Big(frac{1}{n}xBig)^m=sum_{i=1}^{m}a_{i}F(x)Big(frac{1}{n}xBig)^{m-i}
]
即在未结束的串后接上名字一定会结束,但在这之前可能会提前结束,其中(a_{i}=0/1),表示(s[1,i])是否为串(s)的(border)。
对第一个式子求导并化简,有:
[F'(x)=(x-1)G'(x)+G(x)
]
在第二个式子中带入(x=1),有:
[G(1)=sum_{i=1}^{m} a_{i} n^{i}
]
所以:
[E(x)=F'(1)=G(1)=sum_{i=1}^m a_{i} n^{i}
]
对于(a_{i}),(kmp)求即可。
代码
#include<cstdio>
#define N 100005
using namespace std;
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
const int P=10000;
int n,T,m,s[N],nex[N],pw[N];
int main(){
n=In(); T=In();
while(T--){
m=In(); for(int i=1;i<=m;++i) s[i]=In();
pw[0]=1; for(int i=1;i<=m;++i) pw[i]=pw[i-1]*n%P;
for(int i=2,j=0;i<=m;++i){
while(j&&s[j+1]!=s[i]) j=nex[j];
if(s[j+1]==s[i]) ++j; nex[i]=j;
}
int sum=0;
for(int i=m;i;i=nex[i]) sum=(sum+pw[i])%P;
printf("%.4d
",sum);
}
return 0;
}