题目:
有一个游戏,一开始有个数 x x x,每轮游戏可以在 [ 0 , x ] [0,x] [0,x]的范围内随机找到一个数 y y y,并令 x = y x=y x=y。现在给定一个长度为 n + 1 n+1 n+1的序列 p p p,对于 ∀ i ∈ [ 0 , n ] , p i \forall i \in [0,n],p_i ∀i∈[0,n],pi表示一开始的数 x x x是 i i i的概率,问经过 m m m轮游戏后留下的数是 i i i的概率, 0 ≤ i ≤ n 0 \le i \le n 0≤i≤n。给定的和要求的概率都是模998244353意义下的。
( 1 ≤ n ≤ 1 0 5 , 0 ≤ m ≤ 1 0 18 , 0 ≤ p i < 998244353 ) (1 \le n \le 10^5,0 \le m \le 10^{18},0 \le p_i < 998244353) (1≤n≤105,0≤m≤1018,0≤pi<998244353)
题解:
首先可以想到一个 d p dp dp,令 f k , i f_{k,i} fk,i表示第 k k k轮后留下的数是 i i i的概率,转移方程为 f k , i = ∑ j = i n f k − 1 , j 1 j + 1 \displaystyle f_{k,i}=\sum_{j=i}^nf_{k-1,j}\frac{1}{j+1} fk,i=j=i∑nfk−1,jj+11。
令 F k ( x ) F_k(x) Fk(x)为 { f k , n } \{f_{k,n}\} {fk,n}的生成函数,则
F k ( x ) = ∑ i = 0 ∞ f k , i x i = ∑ i = 0 ∞ ∑ j = i n f k − 1 , j 1 j + 1 x i = ∑ i = 0 ∞ ∑ j = i ∞ f k − 1 , j 1 j + 1 x i \displaystyle F_k(x)=\sum_{i=0}^\infty f_{k,i}x^i=\sum_{i=0}^\infty \sum_{j=i}^nf_{k-1,j}\frac{1}{j+1}x^i=\sum_{i=0}^\infty \sum_{j=i}^\infty f_{k-1,j}\frac{1}{j+1}x^i Fk(x)=i=0∑∞fk,ixi=i=0∑∞j=i∑nfk−1,jj+11xi=i=0∑∞j=i∑∞fk−1,jj+11xi
= ∑ j = 0 ∞ f k − 1 , j 1 j + 1 ∑ i = 0 j x i = ∑ j = 0 ∞ f k − 1 , j 1 j + 1 x j + 1 − 1 x − 1 \displaystyle =\sum_{j=0}^\infty f_{k-1,j}\frac{1}{j+1}\sum_{i=0}^jx^i=\sum_{j=0}^\infty f_{k-1,j}\frac{1}{j+1}\frac{x^{j+1}-1}{x-1} =j=0∑∞fk−1,jj+11i=0∑jxi=j=0∑∞fk−1,jj+11x−1xj+1−1
= 1 x − 1 ∑ j = 0 ∞ f k − 1 , j ∫ 1 x t j d t = 1 x − 1 ∫ 1 x ( ∑ j = 0 ∞ f k − 1 , j t j ) d t \displaystyle =\frac{1}{x-1}\sum_{j=0}^\infty f_{k-1,j}\int_{1}^{x} t^j\,{\rm d}t=\frac{1}{x-1}\int_{1}^{x}(\sum_{j=0}^\infty f_{k-1,j} t^j)\,{\rm d}t =x−11j=0∑∞fk−1,j∫1xtjdt=x−11∫1x(j=0∑∞fk−1,jtj)dt
= 1 x − 1 ∫ 1 x F k − 1 ( t ) d t \displaystyle =\frac{1}{x-1}\int_{1}^{x}F_{k-1}(t)\,{\rm d}t =x−11∫1xFk−1(t)dt
积分下限为0的变限积分比较好处理,所以
F k ( x ) = 1 x − 1 ∫ 0 x − 1 F k − 1 ( t + 1 ) d t \displaystyle F_k(x)=\frac{1}{x-1}\int_{0}^{x-1}F_{k-1}(t+1)\,{\rm d}t Fk(x)=x−11∫0x−1Fk−1(t+1)dt
F k ( x + 1 ) = 1 x ∫ 0 x F k − 1 ( t + 1 ) d t \displaystyle F_k(x+1)=\frac{1}{x}\int_{0}^{x}F_{k-1}(t+1)\,{\rm d}t Fk(x+1)=x1∫0xFk−1(t+1)dt
令 G k ( x ) = F k ( x + 1 ) G_k(x)=F_k(x+1) Gk(x)=Fk(x+1),得
G k ( x ) = 1 x ∫ 0 x G k − 1 ( t ) d t \displaystyle G_k(x)=\frac{1}{x}\int_{0}^{x}G_{k-1}(t)\,{\rm d}t Gk(x)=x1∫0xGk−1(t)dt
两边展开,得
∑ i = 0 ∞ g k , i x i = ∑ i = 0 ∞ g k − 1 , i i + 1 x i \displaystyle \sum_{i=0}^\infty g_{k,i}x^i=\sum_{i=0}^\infty \frac{g_{k-1,i}}{i+1}x^i i=0∑∞gk,ixi=i=0∑∞i+1gk−1,ixi
所以
g k , i = g k − 1 , i i + 1 \displaystyle g_{k,i}=\frac{g_{k-1,i}}{i+1} gk,i=i+1gk−1,i
g m , i = g 0 , i ( i + 1 ) m \displaystyle g_{m,i}=\frac{g_{0,i}}{(i+1)^m} gm,i=(i+1)mg0,i
那么现在的问题是 { f k , n } \{f_{k,n}\} {fk,n}和 { g k , n } \{g_{k,n}\} {gk,n}之间怎么变换的。
先来看 { f k , n } \{f_{k,n}\} {fk,n}变换到 { g k , n } \{g_{k,n}\} {gk,n}。
G k ( x ) = F k ( x + 1 ) G_k(x)=F_k(x+1) Gk(x)=Fk(x+1)
∑ i = 0 ∞ g k , i x i = ∑ i = 0 ∞ f k , i ( x + 1 ) i = ∑ i = 0 ∞ f k , i ∑ j = 0 i ( i j ) x j = ∑ i = 0 ∞ ( ∑ j = i ∞ ( j i ) f k , j ) x i \displaystyle \sum_{i=0}^\infty g_{k,i}x^i=\sum_{i=0}^\infty f_{k,i}(x+1)^i=\sum_{i=0}^\infty f_{k,i}\sum_{j=0}^i\dbinom{i}{j}x^j=\sum_{i=0}^\infty (\sum_{j=i}^\infty \dbinom{j}{i}f_{k,j})x_i i=0∑∞gk,ixi=i=0∑∞fk,i(x+1)i=i=0∑∞fk,ij=0∑i(ji)xj=i=0∑∞(j=i∑∞(ij)fk,j)xi
所以
g k , i = ∑ j = i ∞ ( j i ) f k , j = ∑ j = i ∞ j ! i ! ( j − i ) ! f k , j \displaystyle g_{k,i}=\sum_{j=i}^\infty \dbinom{j}{i}f_{k,j}=\sum_{j=i}^\infty \frac{j!}{i!(j-i)!}f_{k,j} gk,i=j=i∑∞(ij)fk,j=j=i∑∞i!(j−i)!j!fk,j
i ! g k , i = ∑ j = i ∞ j ! ( j − i ) ! f k , j = ∑ j = i n j ! ( j − i ) ! f k , j \displaystyle i!g_{k,i}=\sum_{j=i}^\infty \frac{j!}{(j-i)!}f_{k,j}=\sum_{j=i}^n \frac{j!}{(j-i)!}f_{k,j} i!gk,i=j=i∑∞(j−i)!j!fk,j=j=i∑n(j−i)!j!fk,j
令 r f k , n − j = j ! f k , j \displaystyle rf_{k,n-j}=j!f_{k,j} rfk,n−j=j!fk,j,可得
i ! g k , i = ∑ j = i n r f k , n − j ( j − i ) ! = ∑ j + h = n − i r f k , h j ! \displaystyle i!g_{k,i}=\sum_{j=i}^n \frac{rf_{k,n-j}}{(j-i)!}=\sum_{j+h=n-i}\frac{rf_{k,h}}{j!} i!gk,i=j=i∑n(j−i)!rfk,n−j=j+h=n−i∑j!rfk,h
显然右式是 { r f k , n } \{rf_{k,n}\} {rfk,n}和 { 1 n ! } \{\frac{1}{n!}\} {n!1}的卷积。
再来看 { g k , n } \{g_{k,n}\} {gk,n}变换到 { f k , n } \{f_{k,n}\} {fk,n}。
g k , i = ∑ j = i ∞ ( j i ) f k , j \displaystyle g_{k,i}=\sum_{j=i}^\infty \dbinom{j}{i}f_{k,j} gk,i=j=i∑∞(ij)fk,j可二项式反演得
f k , i = ∑ j = i ∞ ( − 1 ) j − i ( j i ) g k , j \displaystyle f_{k,i}=\sum_{j=i}^\infty (-1)^{j-i}\dbinom{j}{i}g_{k,j} fk,i=j=i∑∞(−1)j−i(ij)gk,j
i ! f k , i = ∑ j = i n ( − 1 ) j − i j ! ( j − i ) ! g k , j \displaystyle i!f_{k,i}=\sum_{j=i}^n(-1)^{j-i}\frac{j!}{(j-i)!}g_{k,j} i!fk,i=j=i∑n(−1)j−i(j−i)!j!gk,j
令 r g k , n − j = j ! g k , j rg_{k,n-j}=j!g_{k,j} rgk,n−j=j!gk,j,可得
i ! f k , i = ∑ j = i n ( − 1 ) j − i ( j − i ) ! r g k , n − j = ∑ j + h = n − i ( − 1 ) j j ! r g k , h \displaystyle i!f_{k,i}=\sum_{j=i}^n\frac{(-1)^{j-i}}{(j-i)!}rg_{k,n-j}=\sum_{j+h=n-i}\frac{(-1)^j}{j!}rg_{k,h} i!fk,i=j=i∑n(j−i)!(−1)j−irgk,n−j=j+h=n−i∑j!(−1)jrgk,h
右式为 { r g k , n } \{rg_{k,n}\} {rgk,n}和 { ( − 1 ) n n ! } \{\frac{(-1)^n}{n!}\} {n!(−1)n}的卷积。
两遍 N T T NTT NTT即可。
复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;
#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=2e5+5;
ll read(){
ll 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*10+ch-'0';ch=getchar();}
return x*f;
}
namespace Ploynomial{
const ll mod=998244353,G=3;
int rev[maxn<<1];
ll qpow(ll a,ll p=mod-2){
ll res=1;
while(p){
if(p&1)res=res*a%mod;
a=a*a%mod;
p>>=1;
}
return res;
}
ll invG=qpow(G);
void print(ll *f,int n){
for(int i=0;i<n;i++)printf("%lld ",f[i]);
puts("");
}
void Rev(ll *f,int n){
for(int i=0;i<n;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)?n>>1:0);
if(i<rev[i])swap(f[i],f[rev[i]]);
}
}
ll fix(ll x){
return (x%mod+mod)%mod;
}
void NTT(ll *f,int n,int flag){//1:DFT -1:IDFT
Rev(f,n);
for(int i=1;i<n;i<<=1){
ll wn=qpow(flag>0?G:invG,(mod-1)/(2*i));
for(int j=0;j<n;j+=2*i){
ll w=1;
for(int k=0;k<i;k++){
ll tmp=w*f[j+k+i]%mod;
f[j+k+i]=fix(f[j+k]-tmp);
f[j+k]=fix(f[j+k]+tmp);
w=w*wn%mod;
}
}
}
if(flag<0){
ll invn=qpow(n);
for(int i=0;i<n;i++)
f[i]=f[i]*invn%mod;
}
}
//加法卷积
ll f1[maxn<<1],g1[maxn<<1];
void Mul(ll *f,int n,ll *g,int m,ll *h){
int N;
for(N=1;N<n+m-1;N<<=1);
copy(f,f+n,f1);
fill(f1+n,f1+N,0);
copy(g,g+m,g1);
fill(g1+m,g1+N,0);
NTT(f1,N,1);
NTT(g1,N,1);
for(int i=0;i<N;i++)h[i]=f1[i]*g1[i]%mod;
NTT(h,N,-1);
fill(h+n+m-1,h+N,0);
fill(f1,f1+N,0);
fill(g1,g1+N,0);
}
//多项式求逆 g!=f
ll inv_t[maxn<<1];
void Inv(ll *f,int n,ll *g){
int N;
for(N=1;N<n;N<<=1);
fill(g,g+N,0);
g[0]=qpow(f[0]);
for(int i=2;i<=N;i<<=1){
copy(f,f+i,inv_t);
fill(inv_t+i,inv_t+(i<<1),0);
NTT(g,i<<1,1);
NTT(inv_t,i<<1,1);
for(int j=0;j<(i<<1);j++)
g[j]=fix(2*g[j]-g[j]*g[j]%mod*inv_t[j]%mod);
NTT(g,i<<1,-1);
fill(g+i,g+(i<<1),0);
}
fill(g+n,g+N,0);
fill(inv_t,inv_t+N,0);
}
//求导
int Deriv(ll *f,int n,ll *h){
for(int i=1;i<n;i++){
h[i-1]=f[i]*i%mod;
}
return n-1;
}
//积分
ll inv[maxn];
int Integ(ll *f,int n,ll *h){
inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
}
for(int i=n;i>=1;i--){
h[i]=f[i-1]*inv[i]%mod;
}
h[0]=0;
return n+1;
}
//多项式开根 g!=f
ll sqrt_t[maxn<<1],sqrt_t2[maxn<<1];
void Sqrt(ll *f,int n,ll *g){
int N;
for(N=1;N<n;N<<=1);
fill(g,g+N,0);
g[0]=1;
ll inv2=qpow(2);
for(int i=2;i<=N;i<<=1){
Inv(g,i,sqrt_t);
NTT(sqrt_t,i<<1,1);
NTT(g,i<<1,1);
copy(f,f+i,sqrt_t2);
fill(sqrt_t2+i,sqrt_t2+(i<<1),0);
NTT(sqrt_t2,i<<1,1);
for(int j=0;j<(i<<1);j++){
g[j]=(g[j]*g[j]%mod+sqrt_t2[j])%mod*inv2%mod*sqrt_t[j]%mod;
}
NTT(g,i<<1,-1);
fill(g+i,g+(i<<1),0);
}
fill(g+n,g+N,0);
}
//多项式除法,已知f,g,deg(f)=n,deg(g)=m求q,r,deg(q)=n-m,deg(r)<m,满足f=g*q+r
void Reverse(ll *f,int n){
for(int i=0;i<n/2;i++)swap(f[i],f[n-1-i]);
}
ll div_t[maxn<<1];
void Div(ll *f,int n,ll *g,int m,ll *q,ll *r){
Reverse(f,n);
Reverse(g,m);
Inv(g,n-m+1,div_t);
Mul(f,n,div_t,n-m+1,q);
Reverse(q,n-m+1);
Reverse(g,m);
Reverse(f,n);
Mul(g,m,q,n-m+1,div_t);
for(int i=0;i<m-1;i++)r[i]=fix(f[i]-div_t[i]);
}
//多项式ln
ll ln_t[maxn<<1],ln_t2[maxn<<1];
void Ln(ll *f,int n,ll *h){
Inv(f,n,ln_t);
Deriv(f,n,ln_t2);
Mul(ln_t,n,ln_t2,n-1,h);
fill(h+n-1,h+2*n,0);
// for(int i=n-1;i<2*n-1;i++)h[i]=0;
Integ(h,n-1,h);
fill(ln_t,ln_t+n,0);
fill(ln_t2,ln_t2+n,0);
}
//多项式exp g!=f 保证f[0]=0
ll exp_t[maxn<<1];
void Exp(ll *f,int n,ll *g){
int N;
for(N=1;N<n;N<<=1);
fill(g,g+N,0);
g[0]=1;
for(int i=2;i<=N;i<<=1){
Ln(g,i,exp_t);
for(int j=0;j<i;j++){
exp_t[j]=fix(f[j]-exp_t[j]);
}
exp_t[0]=(exp_t[0]+1)%mod;
Mul(exp_t,i,g,i,g);
fill(g+i,g+2*i,0);
}
fill(g+n,g+N,0);
fill(exp_t,exp_t+N,0);
}
//多项式快速幂,k可以很大,先用mod取模
ll pow_t[maxn<<1];
void Pow(ll *f,int n,ll k,ll *g){
Ln(f,n,pow_t);
for(int i=0;i<n;i++)pow_t[i]=pow_t[i]*k%mod;
Exp(pow_t,n,g);
}
}
#define Ploy Ploynomial
int n;
ll m;
ll f[maxn<<1],fac[maxn],rfac[maxn],g[maxn<<1],h[maxn<<1];
void init(int n){
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%Ploy::mod;
rfac[n]=Ploy::qpow(fac[n]);
for(int i=n-1;i>=0;i--){
rfac[i]=rfac[i+1]*(i+1)%Ploy::mod;
}
}
int main(void){
// freopen("in.txt","r",stdin);
scanf("%d%lld",&n,&m);
init(n);
for(int i=0;i<=n;i++){
scanf("%lld",&f[n-i]);
f[n-i]=f[n-i]*fac[i]%Ploy::mod;
}
Ploy::Mul(f,n+1,rfac,n+1,f);
for(int i=0;i<=n;i++){
g[n-i]=f[n-i]*Ploy::qpow(Ploy::qpow(i+1,m))%Ploy::mod;
}
int flag=1;
for(int i=0;i<=n;i++){
h[i]=flag*rfac[i]%Ploy::mod;
flag=Ploy::mod-flag;
}
Ploy::Mul(g,n+1,h,n+1,g);
for(int i=0;i<=n;i++){
f[i]=g[n-i]*rfac[i]%Ploy::mod;
}
for(int i=0;i<=n;i++){
printf("%lld ",f[i]);
}
puts("");
return 0;
}