【题目】
CF
初始有一个数字
x
∈
[
0
,
n
]
x\in [0,n]
x∈[0,n],给出它取每一个值的概率。接下来进行
m
m
m轮游戏,每轮游戏等概率选择一个数
y
∈
[
0
,
x
]
y\in[0,x]
y∈[0,x],然后令
x
=
y
x=y
x=y,求最终
x
=
0
…
n
x=0\dots n
x=0…n每个值的概率分别是多少,答案对
998244353
998244353
998244353取模。
n
≤
1
0
5
,
m
≤
1
0
18
n\leq 10^5,m\leq 10^{18}
n≤105,m≤1018
【解题思路】
首先写出一个朴素的
DP
\text{DP}
DP,令
f
i
,
j
f_{i,j}
fi,j表示到第
i
i
i轮,数字为
j
j
j的概率,那么有:
f
i
,
j
=
∑
k
=
i
n
f
i
−
1
,
k
k
+
1
f_{i,j}=\sum_{k=i}^n\frac {f_{i-1,k}} {k+1}
fi,j=k=i∑nk+1fi−1,k
将这个东西写成转移矩阵的形式,可以发现这是一个上三角矩阵,且系数十分优美,第
i
i
i列的非零元素为
1
i
\frac 1 i
i1,共
n
+
1
n+1
n+1列。
然后我们也可以很轻松地得到矩阵的特征根方程和其特征根,即:
f
(
λ
)
=
∏
i
=
1
n
+
1
(
λ
−
1
i
)
f(\lambda)=\prod_{i=1}^{n+1}(\lambda -\frac 1 i)
f(λ)=i=1∏n+1(λ−i1)
于是可以大概通过常系数线性递推做到
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)吧。
不会线代的我滚粗了。
上面当我什么都没写吧。我们考虑令
f
i
f_i
fi的生成函数为
F
(
x
)
F(x)
F(x),
f
i
+
1
f_{i+1}
fi+1的生成函数为
F
^
(
x
)
\hat{F}(x)
F^(x)则有:
F
(
x
)
=
∑
i
=
0
n
f
i
x
i
F(x)=\sum_{i=0}^n f_ix_i
F(x)=i=0∑nfixi
F
^
(
x
)
=
∑
i
=
0
n
x
i
∑
j
=
i
n
f
j
j
+
1
=
∑
j
=
0
n
f
j
j
+
1
∑
i
=
0
j
x
i
=
∑
j
=
0
n
f
j
j
+
1
⋅
x
j
+
1
−
1
x
−
1
=
1
x
−
1
∑
j
=
0
n
f
j
∫
1
x
t
j
d
t
=
∫
1
x
F
(
t
)
d
t
x
−
1
\begin{aligned} \hat{F}(x) =&\sum_{i=0}^nx^i\sum_{j=i}^n \frac {f_j} {j+1}\\ =& \sum_{j=0}^n \frac {f_j} {j+1} \sum_{i=0}^j x^i\\ =& \sum_{j=0}^n\frac {f_j} {j+1} \cdot \frac {x^{j+1}-1}{x-1}\\ =& \frac 1 {x-1} \sum_{j=0}^n f_j \int_{1}^x t^j \mathrm{d}t\\ =& \frac {\int_{1}^x F(t)\mathrm{d} t}{x-1} \end{aligned}
F^(x)=====i=0∑nxij=i∑nj+1fjj=0∑nj+1fji=0∑jxij=0∑nj+1fj⋅x−1xj+1−1x−11j=0∑nfj∫1xtjdtx−1∫1xF(t)dt
这个形式并不那么优美,于是令
G
(
x
)
=
F
(
x
+
1
)
G(x)=F(x+1)
G(x)=F(x+1),则有:
∫
1
x
+
1
F
(
t
)
d
t
x
+
1
−
1
⇒
∫
0
x
G
(
t
)
d
t
x
\frac {\int_{1}^{x+1} F(t)\mathrm{d} t}{x+1-1} \Rightarrow \frac {\int_{0}^x G(t)\mathrm{d} t}{x}
x+1−1∫1x+1F(t)dt⇒x∫0xG(t)dt
好像就很优美了,可以发现
g
^
i
=
g
i
i
+
1
\hat{g}_i=\frac {g_i} {i+1}
g^i=i+1gi,那么实际上就是每个位置乘了一个快速幂而已。
接下来考虑
f
,
g
f,g
f,g的关系,我们有:
∑
i
=
0
n
g
i
x
i
=
∑
i
=
0
n
f
i
(
x
+
1
)
i
=
∑
i
=
0
n
f
i
∑
j
=
0
i
(
i
j
)
x
j
\sum_{i=0}^n g_ix^i=\sum_{i=0}^n f_i(x+1)^i=\sum_{i=0}^nf_i\sum_{j=0}^i {i \choose j} x^j
i=0∑ngixi=i=0∑nfi(x+1)i=i=0∑nfij=0∑i(ji)xj
比较系数后可以得到:
g
i
=
∑
j
=
i
n
(
j
i
)
f
j
g_i=\sum_{j=i}^n {j\choose i}f_j
gi=j=i∑n(ij)fj
然后二项式反演一下:
f
i
=
∑
j
=
i
n
(
−
1
)
j
−
i
(
j
i
)
g
j
f_{i}=\sum_{j=i}^n (-1)^{j-i} {j\choose i} g_j
fi=j=i∑n(−1)j−i(ij)gj
上面两个东西将系数拆开以后移下项就是一个卷积的形式了,以第二个为栗子:
i
!
f
i
=
∑
j
=
i
n
(
−
1
)
j
−
i
(
j
−
i
)
!
j
!
g
j
i!f_i=\sum_{j=i}^n \frac {(-1)^{j-i}} {(j-i)!} j!g_j
i!fi=j=i∑n(j−i)!(−1)j−ij!gj
这个东西怎么卷呢?一种很优秀的方式是考虑对应位置。比如上面这个东西,我们设
j
−
i
j-i
j−i的部分是
A
A
A,
j
j
j的部分是
B
B
B。那么先看第
n
n
n项的对应,那么第
n
n
n项是由
A
A
A的第
0
0
0个位置和
B
B
B的第一个位置相乘贡献的。第
n
−
1
n-1
n−1项是由
A
A
A的第
1
1
1个位置和
B
B
B的第
n
n
n个位置,
A
A
A的第
0
0
0个位置和
B
B
B的第
n
−
1
n-1
n−1个位置贡献。也就是说是一个小对应小,大对应大的卷积,我们需要将一个部分翻转。
将 A A A翻转后将 A , B A,B A,B进行卷积,再看贡献到的位置,不难发现原来第 n n n项到了 2 n 2n 2n的位置,第 n − 1 n-1 n−1项到了 2 n − 1 2n-1 2n−1的位置。于是将数组向左平移 n n n位即是答案了。
那么我们就根据上面两条柿子,先用初始的 f 0 f_0 f0求出 g 0 g_0 g0,然后对 g g g的每一位乘个快速幂,再用 g m g_m gm求出 f m f_m fm即可。
复杂度 O ( n log n ) O(n\log n) O(nlogn)
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=262333,mod=998244353,G=3;
namespace IO
{
ll read()
{
ll ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x>9)write(x/10);putchar(x%10^48);}
void writesp(int x){write(x);putchar(' ');}
}
using namespace IO;
namespace Math
{
int inv[N],fac[N],ifac[N];
int upm(int x){return x>=mod?x-mod:(x<0?x+mod:x);}
void up(int &x,int y){x=upm(x+y);}
int mul(int x,int y){return 1ll*x*y%mod;}
ll qpow(ll x,ll y){ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
ll getinv(int x){return qpow(x,mod-2);}
void initmath()
{
inv[0]=inv[1]=1;for(int i=2;i<N;++i) inv[i]=mul(mod-mod/i,inv[mod%i]);
fac[0]=1;for(int i=1;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=getinv(fac[N-1]);for(int i=N-2;~i;--i)ifac[i]=mul(ifac[i+1],i+1);
}
int m,L,rev[N];
void ntt(int *a,int n,int op)
{
for(int i=0;i<n;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1;i<n;i<<=1)
{
int wn=qpow(G,(mod-1)/(i<<1));
if(!~op) wn=getinv(wn);
for(int j=0;j<n;j+=i<<1)
{
int w=1;
for(int k=0;k<i;++k,w=mul(w,wn))
{
int x=a[j+k],y=mul(w,a[i+j+k]);
a[j+k]=upm(x+y);a[i+j+k]=upm(x-y);
}
}
}
if(!~op)for(int i=0,iv=getinv(n);i<n;++i)a[i]=mul(a[i],iv);
}
void reget(int n)
{
for(m=1,L=0;m<n;m<<=1,++L);
for(int i=0;i<m;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
}
void polymult(int *a,int *b,int *c,int dega,int degb)
{
static int A[N],B[N];
reget(dega+degb-1);copy(a,a+dega,A);copy(b,b+degb,B);
ntt(A,m,1);ntt(B,m,1);
for(int i=0;i<m;++i) A[i]=mul(A[i],B[i]);
ntt(A,m,-1);
copy(A,A+dega+degb-1,c);fill(c+dega+degb-1,c+m,0);fill(A,A+m,0);fill(B,B+m,0);
}
}
using namespace Math;
namespace DreamLolita
{
int n;ll m;
int p[N],f[N],g[N],h[N];
void solution()
{
initmath();n=read();m=read();
for(int i=0;i<=n;++i) p[i]=read();
for(int i=0;i<=n;++i) h[i]=ifac[i],f[i]=mul(p[i],fac[i]);
reverse(h,h+n+1);
polymult(h,f,g,n+1,n+1);
for(int i=0;i<=n;++i) g[i]=mul(g[i+n],ifac[i]),f[i]=0;
for(int i=n+1;i<=n*2;++i) g[i]=0,f[i]=0;
for(int i=0;i<=n;++i) g[i]=mul(mul(g[i],(int)qpow(inv[i+1],m)),fac[i]);
for(int i=0;i<=n;++i) h[i]=mul(h[i],(n-i)&1?mod-1:1);
polymult(g,h,f,n+1,n+1);
for(int i=0;i<=n;++i) f[i]=mul(f[i+n],ifac[i]);
for(int i=0;i<=n;++i) writesp(f[i]);
}
}
int main()
{
#ifdef Durant_Lee
freopen("CF947E.in","r",stdin);
freopen("CF947E.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}