【XSY3955】作曲家(概率dp,生成函数,kmp)
题面
题解
这种序列相似的见过很多次,但一直不会做,今天终于知道一个套路了。
记 \(s\) 与 \(t\) 相似为 \(s\sim t\)。显然这个 “相似” 是有传递性的,即若 \(a\sim c\) 且 \(b\sim c\),那么 \(a\sim b\)。
前置知识/定义
概率相关的定义
定义 \(\overline{A}\) 表示事件 “事件 \(A\) 不发生”。
定义 \(P(A)\) 表示事件 \(A\) 发生的概率。
定义 \(P(A|B)\) 表示在事件 \(B\) 发生的前提下(即钦定 \(B\) 已经发生率),事件 \(A\) 发生的概率。
形状序列
定义一个序列 \(s\) 的形状序列为另一个长度也为 \(|s|\) 的序列 \(t\),满足对于 \(1\leq i\leq |s|\):
- 若 \(s_i\) 在 \(s[1,i-1]\) 中没有出现过,那么 \(t_i=0\)。
- 否则,找到 \(s_i\) 在 \(s[1,i-1]\) 中最后一次出现的位置,记作 \(j\),那么 \(t_i=i-j\)。
记 \(s\) 的形状序列为 \(\operatorname{shape}(s)\),那么 \(s\sim t \iff \operatorname{shape}(s)=\operatorname{shape}(t)\)。
合法形状序列
定义 \(n_0(t)\) 表示序列 \(t\) 中 \(0\) 的个数。
定义合法序列为一个序列 \(s\),满足 \(s\) 中的每一个数在数集 \([1,n]\cap \mathbb{Z}\) 内。
对于一个序列 \(t\) 来说,如果 \(t\) 能成为某个合法序列的形状序列,那么称 \(t\) 为合法形状序列。
容易知道整数序列 \(t\) 是合法形状序列当且仅当以下三个条件成立:(下面的 \(n\) 和本题中的 \(n\) 定义一样,为数集大小)
- \(n_0(t)\leq n\)。即 \(t\) 中的不同的数的个数不能超过数集大小。
- \(\forall 1\leq i\leq |t|\),若 \(t_i\neq 0\),有 \(1\leq i-t_i<i\)。
- \(\forall 1\leq i<j\leq|t|\),若 \(t_i,t_j\neq 0\),有 \(i-t_i\neq j-t_j\)。
任意序列的形状序列都是合法形状序列。
对于一个合法形状序列 \(t\) 来说,考虑 \(t\) 可能是多少种不同序列的形状序列,易知 \(t\) 可能是 \(A_n^{n_0(t)}\) 种不同序列的形状序列。
子形状序列
对于一个合法形状序列 \(t\) 和整数 \(1\leq \ell\leq r\leq |t|\) 来说,定义 \(t\) 关于区间 \([l,r]\) 的子形状序列为一个长度为 \(r-l+1\) 的序列 \(t'\),满足对于所有的 \(1\leq i\leq r-l+1\)(令 \(j=l+i-1\))有:
把合法形状序列 \(t\) 关于区间 \([l,r]\) 的子形状序列记作 \(\operatorname{subshape}(t,l,r)\)。
若 \(s\) 的形状序列为 \(t\),容易发现 \(\operatorname{subshape}(t,l,r)=\operatorname{shape}(s[l,r])\)。
本题的分析
首先为了方便,记 \(\hat{a}=\operatorname{shape}(a)\)。
首先注意到至少要先生成 \(m\) 次,所以不妨设生成了 \(m+k\) 次的概率为 \(p_k\),那么答案即为 \(ans=m+\sum\limits_{k=0}^{\infty}k\cdot p_k\)。
将题目要求作一个等价转化:即使宣告生成停止,仍然可以继续生成(但之后不能再宣告生成停止了),可得一无限随机序列 \(S\),现在我们求的就是 “宣告停止时间” 的期望。
接下来我们会记录一个数组 \(q\)。
首先,记连续生成 \(m\) 次随机数所得序列与 \(a\) 相似的概率为 \(q_m\),那么 \(q_m=n^{-m}A_n^{n_0(\hat{a})}\)。
定义:
-
事件 \(A_k\):\(S[k+1,k+m]\sim a\)。那么 \(\forall i\geq 0,P(A_i)=q_m\)。
-
事件 \(B_k\):\(m+k\) 为宣告停止时间。那么 \(p_k=P(B_k)\)。
显然 \(p_k=P(B_k)=P(A_k\cap \overline{B_0}\cap \overline{B_1}\cap \cdots\cap \overline{B_{k-1}})\)。
又由于事件 \(B_i\) 是互斥的,所以:
接下来只需计算 \(P(A_k|B_i)\):
-
当 \(i\leq k-m\) 时,事件 \(A_k\) 与事件 \(B_i\) 相互独立,所以 \(P(A_k|B_i)=P(A_k)=q_m\)。
-
当 \(k-m<i<k\) 时,设 \(\ell=k-i\)。
下面说的东西要自己画图理解。
一方面,由于我们钦定了 \(B_i\) 成立,所以 \(S[i+1,i+m]\sim a[1,m]\),所以 \(S[i+\ell+1,i+m]\sim a[\ell+1,m]\),即 \(S[k+1,i+m]\sim a[\ell+1,m]\);
另一方面,如果 \(A_k\) 成立,就有 \(S[k+1,k+m]\sim a[1,m]\),所以 \(S[k+1,k+m-\ell]\sim a[1,m-\ell]\),即 \(S[k+1,i+m]\sim a[1,m-\ell]\)。
又由相似的传递性可知 \(a[\ell+1,m]\sim a[1,m-\ell]\)。
所以在 \(B_i\) 发生的前提下,\(A_k\) 发生的必要条件是 \(a[\ell+1,m]\sim a[1,m-\ell]\)。所以若 \(a[\ell+1,m]\not\sim a[1,m-\ell]\),恒有 \(P(A_k|B_{i})=0\)。发现这只与 \(\ell\) 有关,所以此时记 \(P(A_k|B_i)=q_{\ell}=0\)。
接下来考虑 \(a[1,m-\ell]\sim a[\ell+1,m]\) 成立的情况,可得 \(\operatorname{subshape}(\hat{a},1,m-\ell)=\operatorname{subshape}(\hat{a},\ell+1,m)\)。
注意到 \(\operatorname{subshape}(\hat{a},1,m-\ell)=\hat{a}[1,m-\ell]\),所以可得 \(\hat{a}[1,m-\ell]=\operatorname{subshape}(\hat{a},\ell+1,m)\)。
又由于我们刚刚由 \(B_i\) 成立的前提得到了 \(S[k+1,i+m]\sim a[\ell+1,m]\),所以又可得 \(\hat{a}[1,m-\ell]=\operatorname{shape}(S[k+1,i+m])=\operatorname{shape}(S[k+1,k+m-\ell])\)。
现在我们着眼 \(T[1,m]=S[k+1,k+m]\),那么要解决的就是这么一个问题:我们现在已经有了 \(a[1,m-\ell]\sim T[1,m-\ell]\),那么当 \(T[m-\ell+1,m]\) 的每个数都在 \(1\sim n\) 里面随机生成时,最后 \(a[1,m]\sim T[1,m]\) 的概率是多少?
为计算概率,可以逐项确定序列。当 \(\hat{a}_i\neq 0\) 时,该项被唯一确定,所以对概率贡献一个因子 \(n^{-1}\);当 \(\hat{a}_i=0\) 时,该项可以从之前未出现的字符中任取,所以对概率贡献的因子是 \(n^{-1}(n - n_0(\hat{a}[1, i - 1]))\)。综合起来,概率为 \(n^{-\ell}A_{n-n_0(\hat{a}[1,m-\ell])}^{n_0(\hat{a}[m-\ell+1,m])}\),也是一个只和 \(\ell\) 有关的量,记为 \(q_{\ell}\)。
综上所述,可以列式:
那么:
移项:
往生成函数的方向靠:
设 \(P(x)\) 为 \(p_k\) 的生成函数(即 \(P(x)=p_0+p_1x+p_2x^2+\cdots\)),那么有:
(注意 \(\sum\limits_{\ell=1}^{\min(k,m-1)}q_{\ell}x^{\ell}p_{k-\ell}x^{k-\ell}\) 中 \(\ell\) 的上界设为 \(\min(k,m-1)\) 是为了防止越界,但写成生成函数的形式后就不用担心越界的问题了)
(注意 \(\sum\limits_{i=0}^{k-m}q_mx^{k-i}p_ix^i\) 中 \(i\) 的取值范围是 \([0,k-m]\),所以 \(k-i\) 的取值范围是 \([m,k]\))
提公因式:
设 \(P(x)=Q^{-1}(x)\),那么:
注意到若一多项式 \(f(x)=\sum\limits_{i\geq 0}a_ix^i\),有 \(f'(x)=\sum\limits_{i\geq 1}a_iix^{i-1}\)。(多项式求导)
所以答案为:
引理:若 \(f(x),g(x)\) 为多项式,那么 \(\left[\dfrac{g(x)}{f(x)}\right]'=-\dfrac{f'(x)g(x)+f(x)g'(x)}{f^2(x)}\)。(见高中选修2-2,以下有关导数的知识或引理的证明也请参见这本书或自行上网搜索,本文不再阐述太多)
那么有 \(\left[\dfrac{1}{Q(x)}\right]'=-\dfrac{Q'(x)}{Q^2(x)}\)。
发现当 \(x=1\) 时,\(Q(1)=1\),所以 \(\left[\dfrac{1}{Q(1)}\right]'=-\dfrac{Q'(1)}{Q^2(1)}=-Q'(1)\)。
于是现在的问题是求 \(Q'(1)\):
当 \(x=1\) 时,\(mx^{m-1}=m\)。那么现在的问题是求出 \(\left[\dfrac{1-x}{q_m}\left(1+\sum\limits_{\ell=1}^{m-1}q_{\ell}x^{\ell}\right)\right]'\)。
引理:若 \(f(x),g(x)\) 为多项式,那么 \(\big[f(x)g(x)\big]'=f'(x)g(x)+f(x)g'(x)\)。
不妨设 \(f(x)=\dfrac{1-x}{q_m}\),\(g(x)=\left(1+\sum\limits_{\ell=1}^{m-1}q_{\ell}x^{\ell}\right)\),注意到当 \(x=1\) 时 \(f(1)=0\),所以 \(\big[f(1)g(1)\big]'=f'(1)g(1)+f(1)g'(1)=f'(1)g(1)\)。
而 \(f'(x)=\left(\dfrac{1-x}{q_m}\right)'=-\dfrac{1}{q_m}\),所以 \(f'(1)g(1)=-\dfrac{1}{q_m}g(1)=-\dfrac{1}{q_m}\left(1+\sum\limits_{\ell=1}^{m-1}q_{\ell}\right)\)。
所以 \(Q'(1)=m-\dfrac{1}{q_m}\left(1+\sum\limits_{\ell=1}^{m-1}q_{\ell}\right)\)。
所以 \(ans=m+\left[\dfrac{1}{Q(1)}\right]'=m-Q'(1)=\dfrac{1}{q_m}\left(1+\sum\limits_{\ell=1}^{m-1}q_{\ell}\right)\)。
设 \(a[1,m]\) 的所有相似前后缀的长度集合为 \(L_m=\{1\leq k\leq m\ |\ a[1,k]\sim a[m-k+1,m]\}\),注意这里 \(k\) 的范围是可以到 \(m\) 的。
然后暴力把 \(q_m\) 和 \(q_{\ell}\) 的定义式代入,得到:
那么现在只需要求 \(L_m\)。
下面说的东西也要自己画图理解。
注意到,若 \(k,\ell \in L\) 且 \(k>\ell\),那么 \(a[1,\ell] \sim a[m-\ell+1,m]\sim a[k-\ell +1,k]\),也就是说 \(a[1,\ell]\) 和 \(a[k-\ell+1,k]\) 也是 \(a[1,k]\) 的一对相似前后缀。
那么不妨设 \(L_r=\{1\leq k\leq r\ |\ a[1,k]\sim a[r-k+1,r]\}\) 表示 \(a[1,r]\) 的所有相似前后缀的长度集合,\(b_r\) 为 \(L_r\) 集合内除了 \(r\) 以外最大的那个数。那么 \(\forall 1\leq i< b_r\),\(i\) 也在集合 \(L_r\) 内的充要条件是 \(i\) 也在集合 \(L_{b_r}\) 内。
那么我们从 \(r=m\) 开始,不断递归 \(r\gets b_r\),那么遍历到的所有的 \(r\) 就是 \(L_m\) 内所有的数。
那么现在的问题是如何对于每一个 \(1\leq r\leq m\) 求出 \(b_r\)。
发现 \(b_r\) 的定义和 kmp 数组的定义很像,所以直接用类似 kmp 的方法求出所有的 \(b_r\) 即可。
听说这道题推导路线十分经典,但我见都没见过类似的题(((
代码如下:
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
namespace modular
{
const int mod=998244353;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
inline int poww(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
int n,m,a[N],shape[N];
int last[N],n0[N];
int fac[N],pown[N];
int b[N];
vector<int>L;
bool check(int j,int i)
{
return shape[j]==(shape[i]>j?0:shape[i]);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
a[i]=read();
n0[i]=n0[i-1];
if(!last[a[i]]) n0[i]++;
else shape[i]=i-last[a[i]]+1;
last[a[i]]=i;
}
b[1]=0;
for(int i=2,j=0;i<=m;i++)
{
while(j&&!check(j+1,i)) j=b[j];
if(check(j+1,i)) j++;
b[i]=j;
}
int j=m;
while(j)
{
L.push_back(j);
j=b[j];
}
pown[0]=fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
for(int i=1;i<=m;i++) pown[i]=mul(pown[i-1],n);
int ans=0;
for(int i=0,size=L.size();i<size;i++)
{
int k=L[i];
ans=add(ans,mul(pown[k],fac[n-n0[k]]));
}
printf("%d\n",mul(ans,poww(fac[n],mod-2)));
return 0;
}
/*
10 2
1 1
*/