卧薪尝胆,厚积薄发。
CTSC2006 歌唱王国
Date: Sun Mar 10 19:34:23 CST 2019
In Category:
NoCategory
Description:
字符集大小为
$N$
,给定串
$S$
,求:一个随机序列中
$S$
第一次出现的位置期望。
$N,|S|\leqslant10^5$
Solution:
设
$F(x)$
为表达结束时序列长度的概率生成函数,那么答案就是
$F'(1)$
。
定义一个辅助生成函数
$G(x)$
为序列到达
$i$
还没有结束的概率。
那么有:
$$
[x^n]F(x)=[x^{n-1}]G(x)-[x^n]G(x)+[n=0]
$$
那么也就有:
$$
F(x)+G(x)=1+G(x)\times x
$$
设
$a$
为一个
$0/1$
序列,其中第
$i$
项表示
$[1,i]$
是否是一个
$border$
,定义字符串长度为
$l$
,字符集为
$\Sigma$
,那么有:
$$
G(x)\times (\frac 1mx)^L=\sum_{i=1}^LF(x)a_i (\frac 1mx)^{L-i}
$$
这个式子的意义就是,我们往一个还没结束的字符串后面再加这个字符串,那么这样生成的字符串
$S$
一定出现过(最后
$S$
个字符),但是不一定是第一次出现,但是第一次出现一定和最后一次出现相交,那么我们可以枚举相交的长度
$i$
,他一定是原串的一个
$border$
。
将第一个式子两边求导:
$$
F'(x)+G'(x)=G'(x)\times x+G(x)\Longrightarrow F'(1)=G'(1)\times 1+G(x)-G'(1)+G(1)=G(1)
$$
于是我们只要求
$G(1)$
就行了。
再把
$x=1$
代入第二个式子:
$$
G(1)=\sum_{i=1}^LF(1)a_im^i=\sum_{i=1}^La_im^i
$$
就可以在
$O(L)$
的时间内求解了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int m,n,t;
#define MAXN 100010
int s[MAXN];
bool v[MAXN];
int nxt[MAXN];
#define MOD 10000
int power(int a,int b)
{
int res = 1;
for(;b > 0;b = b >> 1,a = 1ll * a * a % MOD)if(b & 1)res = 1ll * res * a % MOD;
return res;
}
int main()
{
scanf("%d%d",&m,&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%d",&s[i]);
for(int i = 2,j = 0;i <= n;++i)
{
while(j && s[i] != s[j + 1])j = nxt[j];
if(s[i] == s[j + 1])++j;
nxt[i] = j;
}
int cur = n;
v[n] = true;
while(nxt[cur] != 0)
{
v[nxt[cur]] = true;
cur = nxt[cur];
}
int ans = 0;
for(int i = 1;i <= n;++i)ans = (ans + v[i] * power(m,i)) % MOD;
if(ans < 1000)putchar('0');
if(ans < 100)putchar('0');
if(ans < 10)putchar('0');
printf("%d\n",ans);
for(int i = 1;i <= n;++i)v[i] = false;
}
return 0;
}
In tag:
数学-组合数学-生成函数
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡