【题目】
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
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;
}