CTSC2006 歌唱王国

歌唱王国

problem

题解

\(f_i\) 表示 \(i\) 步结束的概率,\(g_i\) 表示 \(i\) 步未结束的概率。

\[g_i=f_{i+1}+g_{i+1}\\ g_i(\frac{1}{m})^L=\sum_{j>i 且 j-i是\text{border}} f_j (\frac{1}{m})^{L-(j-i)} \]

第一个转移表示掷一次骰子dice会发生的事情。

第二个转移表示拼一个原串上去会发生的事情。(一定会结束)

solution1

solution2

https://jkloverdcoi.github.io/2019/12/13/bzoj-1152-歌唱王国/
https://www.cnblogs.com/cjyyb/p/10649150.html

要求的是 \(F’(1)\) ,将 (1) 式两边对 \(x\) 求导后代入 \(x=1\),得到

\[F’(x)+G’(x)=x\cdot G’(x)+G(x)\\ F’(1)=G(1) \]

\(x=1\) 代入 (2) 式,得到

\[G(1)=m^L\sum_{i=1}^n a_i\cdot F(1) \cdot (\frac{1}{m})^{L-i}\\ G(1)=\sum_{i=1}^n a_i\cdot F(1) \cdot m^i\\ \]

注意到 \(F(1)=\sum f_i=1\),所以

\[F’(1)=\sum_{i=1}^n a_i\cdot m^i \]

于是只需用 KMP 判断给定序列的每个前缀是不是它的 border 就可以了.

用 %04d 可以达到题目要求的输出效果,当然也可以自己写一下输出.

时间复杂度 \(O(n)\)

CO int N=1e5+10;
int pw[N];
int str[N],nxt[N];

void real_main(){
	int n=read<int>();
	for(int i=1;i<=n;++i) read(str[i]);
	for(int i=2;i<=n;++i){
		int j=nxt[i-1];
		while(j and str[j+1]!=str[i]) j=nxt[j];
		if(str[j+1]==str[i]) ++j;
		nxt[i]=j;
	}
	int ans=0;
	for(int i=n;i;i=nxt[i]) ans=add(ans,pw[i]);
	printf("%04d\n",ans);
}
int main(){
	int m=read<int>();
	pw[0]=1;
	for(int i=1;i<N;++i) pw[i]=mul(pw[i-1],m);
	for(int T=read<int>();T--;) real_main();
	return 0;
}

总结概率生成函数:

  • 优点:处理简洁,易扩展,⽐如可以改成求⽅差,或者说求某⼀项的值。

  • 缺点:列⽅程⽐较不直观,需要⼀定的套路积累和练习(+⼀个/+⼀组)。

posted on 2019-12-26 19:11  autoint  阅读(218)  评论(0编辑  收藏  举报

导航