LGP7445题解
根据期望的线性性,考虑某个节点会做 pushdown 的概率为 \(p_u\),答案显然就是 \(\sum p_u\)。
考虑一个节点不会被做 pushdown 的情况,设这个节点所代表的区间为 \([l,r]\),那么这个节点不会被做 pushdown 当且仅当所有包含这个区间的修改中,加起来的权值和为 \(0\)。
考虑设一次修改会修改到这个区间的概率是 \(c=\frac{l(n-r+1)}{n(n-1)\div 2}\),设 \(f[i]\) 表示 \(i\) 个 \([-1,V]\) 的数加起来为 \(0\) 的概率,那么对于这个节点答案就是:
\[\sum_{i=0}^{m}\binom{m}{i}c^{i}(1-c)^{m-i}(1-f[i])=(1-c)^{m}\sum_{i=0}^{m}(\binom{m}{i}(1-f[i]))(\frac{c}{1-c})^i
\]
求出 \(f[i]\) 后多点求值即可。考虑求解 \(f[i]\)。
显然有 \(f[n]=[x^0](\sum_{i=-1}^{V}x^i)^n(V+2)^{-n}\)。
显然后面这玩意儿 \(V+1\) 是可以对 \(m-1\) 取 \(\min\) 的(考虑 \(m-1\) 个 \(-1\) 只能拼凑 \(m-1\))。设 \(k=\min(V+1,m)\),问题变为求出:
\[f[n]=[x^0](\frac{1-x^{k}}{1-x}\div x)^n
\]
\[f[n]=[x^0](\frac{x(1-x)}{1-x^k})^{-n}
\]
此时使用拉格朗日反演可以得到:
\[[x^0](\frac{x(1-x)}{1-x^k})^{-n}=[x^{n-1}]G'(x)G^{-1}(x)
\]
其中有 \(G(\frac{x-x^2}{1-x^k})=x\)。
因为 \(G(x)\) 和 \(\frac{x-x^2}{1-x^k}\) 互为复合逆,所以有:
\[\frac{G(x)-G^2(x)}{1-G^k(x)}-x=0
\]
牛顿迭代即可。
\[G(x)-G^2(x)=x-xG^k(x)
\]
\[G(x)-G^2(x)+xG^k(x)-x=0
\]
\[y-y^2+xy^k-x
\]
\[\frac{{\rm d}}{{\rm d}y}y-y^2+xy^k-x
\]
\[1-2y+kxy^{k-1}
\]
\[G_0(x)=G(x)-\frac{G(x)-G^2(x)+xG^k(x)-x}{1-2G(x)+kxG^{k-1}(x)}
\]
#include<algorithm>
#include<cstdio>
#include<cctype>
#include<vector>
#define IMP(lim,act) for(int qwq=(lim),i=0;i^qwq;++i)act
const int M=1<<17|5,mod=998244353;
int fac[M<<2],ifac[M<<2],Inv[M<<2],buf[M<<2];int*now=buf,*w[23];
inline void swap(int&a,int&b){
int c=a;a=b;b=c;
}
inline int Add(const int&a,const int&b){
return a+b>=mod?a+b-mod:a+b;
}
inline int Del(const int&a,const int&b){
return b>a?a-b+mod:a-b;
}
inline int max(const int&a,const int&b){
return a>b?a:b;
}
inline int min(const int&a,const int&b){
return a>b?b:a;
}
inline void write(int n){
static char s[10];int top(0);while(s[++top]=n%10^48,n/=10);while(putchar(s[top--]),top);
}
inline int read(){
int n(0);bool typ(false);char s;while(!isdigit(s=getchar()))typ|=s==45;
while(n=n*10+(s&15),isdigit(s=getchar()));return typ?-n:n;
}
inline int pow(int a,int b=mod-2){
int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
}
inline int Getlen(const int&n){
int len(0);while((1<<len)<n)++len;return len;
}
inline void init(const int&n){
const int&m=Getlen(n);w[m]=now;now+=1<<m;Inv[1]=1;
for(int i=2;i<(1<<m);++i)Inv[i]=1ll*(mod-mod/i)*Inv[mod%i]%mod;
w[m][0]=1;w[m][1]=pow(3,mod-1>>m+1);for(int i=2;i<(1<<m);++i)w[m][i]=1ll*w[m][i-1]*w[m][1]%mod;
for(int k=m-1;k>=0&&(w[k]=now,now+=1<<k);--k)IMP(1<<k,w[k][i]=w[k+1][i<<1]);
fac[0]=ifac[0]=1;for(int i=1;i<(1<<m);++i)fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*Inv[i]%mod;
}
struct Poly{
std::vector<int>F;
Poly(){F=std::vector<int>(0);}
Poly(const Poly&G){F=G.F;}
Poly(const std::vector<int>G){F=G;}
Poly(const int&x){*this=Poly();F.push_back(x);}
inline Poly&resize(const int&len){
F.resize(len);return*this;
}
inline bool empty()const{
return F.empty();
}
inline int size()const{
return F.size();
}
inline int&operator[](const int&id){
return F[id];
}
inline void push_back(const int&x){
F.push_back(x);
}
inline Poly&reverse(){
std::reverse(F.begin(),F.end());return*this;
}
inline Poly operator-(){
Poly G;IMP(F.size(),G.push_back(Del(0,F[i])));return G;
}
inline Poly operator>>(const int&x){
Poly G;IMP(F.size()-x,G.push_back(F[i+x]));return G;
}
inline Poly operator<<(const int&x){
Poly G;G.resize(x);IMP(F.size(),G.push_back(F[i]));return G;
}
inline int operator()(const int&x){
int y(1),ans(0);IMP(F.size(),ans=(ans+1ll*F[i]*y)%mod),y=1ll*y*x%mod;return ans;
}
inline void px(Poly G){
F.resize(max(F.size(),G.size()));G.resize(F.size());
for(int i(0);i^F.size();++i)F[i]=1ll*F[i]*G[i]%mod;
}
inline Poly&Der(){
for(int i(1);i^F.size();++i)F[i-1]=1ll*F[i]*i%mod;F.pop_back();return*this;
}
inline Poly&Int(){
F.push_back(0);
for(int i(F.size()-1);i;--i)F[i]=1ll*F[i-1]*::Inv[i]%mod;F[0]=0;return*this;
}
inline void DFT(const int&M){
F.resize(1<<M);
for(int len=F.size()>>1,d=M-1;len;--d,len>>=1)for(int k=0;k^F.size();k+=len<<1){
int*W=w[d],*L=&F[k],*R=&F[k|len],x,y;IMP(len,(x=*L,y=*R)),*L++=Add(x,y),*R++=1ll**W++*Del(x,y)%mod;
}
}
inline void IDFT(const int&M){
F.resize(1<<M);
for(int len=1,d=0;len^F.size();len<<=1,++d)for(int k=0;k^F.size();k+=len<<1){
int*W=w[d],*L=&F[k],*R=&F[k|len],x,y;IMP(len,(x=*L,y=1ll**W++**R%mod)),*L++=Add(x,y),*R++=Del(x,y);
}
const int&k=::pow(F.size());IMP(F.size(),F[i]=1ll*F[i]*k%mod);
for(int i=1;(i<<1)<F.size();++i)swap(F[i],F[F.size()-i]);
}
inline Poly operator+(Poly G)const{
Poly F=this->F;F.resize(max(F.size(),G.size()));G.resize(F.size());
IMP(F.size(),F[i]=Add(F[i],G[i]));return F;
}
inline Poly operator-(Poly G)const{
Poly F=this->F;F.resize(max(F.size(),G.size()));G.resize(F.size());
IMP(F.size(),F[i]=Del(F[i],G[i]));return F;
}
inline Poly operator*(const int&x)const{
Poly F=this->F;IMP(F.size(),F[i]=1ll*F[i]*x%mod);return F;
}
inline Poly operator*(Poly G)const{
Poly F=*this;const int&m=F.size()+G.size()-1,&len=Getlen(m);
F.DFT(len);G.DFT(len);F.px(G);F.IDFT(len);return F.resize(m);
}
inline Poly operator/(Poly G){
Poly F=*this,sav;const int&m=F.size()-G.size()+1;
sav.resize(m);IMP(m,sav[i]=G.size()+i<m?0:G[G.size()-m+i]);
sav.reverse().inv();sav*=F.reverse();
return sav.resize(m).reverse();
}
inline Poly operator%(Poly G){
return(*this-*this/G*G).resize(G.size()-1);
}
inline Poly&inv(){
Poly b1,b2,b3;const int&m=Getlen(F.size());if(!F.empty())b1.push_back(::pow(F[0]));
for(int len=1;len<=m;++len){
b3=b1*2;(b2=F).resize(1<<len);
b1.DFT(len+1);b1.px(b1);b2.DFT(len+1);b1.px(b2);b1.IDFT(len+1);
b1=b3-b1.resize(1<<len);
}
return*this=b1.resize(F.size());
}
inline Poly&ln(){
const int&m=F.size()-1;Poly G=*this;return(this->Der()*=G.inv()).resize(m).Int();
}
inline Poly&exp(){
Poly b1,b2,b3;const int&m=Getlen(F.size());b1.push_back(1);
for(int len=1;len<=m;++len){
b3=b2=b1;b2.resize(1<<len).ln();b2=(*this-b2).resize(1<<len);++b2[0];
b2.DFT(len);b3.DFT(len);b2.px(b3);b2.IDFT(len);b1.resize(1<<len);
IMP(1<<len-1,b1[1<<len-1|i]=b2[1<<len-1|i]);
}
return*this=b1.resize(F.size());
}
inline Poly&sqrt(){
Poly b1,b2;const int&m=Getlen(F.size());b1.push_back(1);
for(int len=1;len<=m;++len){
b2=(b1*2).resize(1<<len).inv();
b1.DFT(len);b1.px(b1);b1.IDFT(len);
b1=((*this+b1).resize(1<<len)*b2).resize(1<<len);
}
return*this=b1.resize(F.size());
}
inline Poly&pow(const int&k){
ln();IMP(F.size(),F[i]=1ll*F[i]*k%mod);exp();
return*this;
}
inline Poly&operator>>=(const int&x){
return*this=operator>>(x);
}
inline Poly&operator<<=(const int&x){
return*this=operator<<(x);
}
inline Poly&operator+=(const Poly&G){
return*this=*this+G;
}
inline Poly&operator-=(const Poly&G){
return*this=*this-G;
}
inline Poly&operator*=(const Poly&G){
return*this=*this*G;
}
inline Poly&operator/=(const Poly&G){
return*this=*this/G;
}
inline Poly&operator%=(const Poly&G){
return*this=*this%G;
}
};
inline Poly resize(Poly F,const int&n){
return F.resize(n);
}
inline Poly reverse(Poly F){
return F.reverse();
}
inline Poly Int(Poly F){
return F.Int();
}
inline Poly Der(Poly F){
return F.Der();
}
inline Poly px(Poly F,Poly G){
return F.px(G),F;
}
inline Poly inv(Poly F){
return F.inv();
}
inline Poly ln(Poly F){
return F.ln();
}
inline Poly exp(Poly F){
return F.exp();
}
inline Poly sqrt(Poly F){
return F.sqrt();
}
inline Poly pow(Poly F,const int&k){
return F.pow(k);
}
int n,m,V,c,q,ans,a[M],b[M],id[M<<2];Poly f,g,F[M<<2],G[M<<2];
inline Poly Newton(const int&n,const int&k){
Poly F,b1,b2;const int&m=Getlen(n);F.push_back(0);
for(int len=1;len<=m;++len){
b1=resize(pow(resize(F>>1,1<<len),k-1)<<k-1,1<<len);b2=resize(b1*F,1<<len);
F-=resize((Poly(1)-F*2+resize(b1*k<<1,1<<len)).inv()*(F-F*F+(b2-Poly(1)<<1)),1<<len);
}
return F.resize(n);
}
inline Poly timesT(Poly F,Poly G,int len=-1){
if(F.empty()||G.empty())return Poly();
const int&n=F.size(),&m=G.size();if(!~len)len=n-m+1;return (F*G.reverse()>>m-1).resize(len);
}
inline void Build(const int&u,const int&L=1,const int&R=q){
if(L==R)return F[u].push_back(1),F[u].push_back(Del(0,a[L]));
const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);F[u]=F[u<<1]*F[u<<1|1];
}
inline void Solve(const int&u,const int&L=1,const int&R=q){
if(L==R)return void(a[L]=G[u][0]);
const int&mid=L+R>>1;G[u<<1]=timesT(G[u],F[u<<1|1]);G[u<<1|1]=timesT(G[u],F[u<<1]);
Solve(u<<1,L,mid);Solve(u<<1|1,mid+1,R);
}
inline void DFS1(const int&u,const int&L=1,const int&R=n){
if(L==R)return;b[id[u]=++q]=2ll*L*(n-R+1)%mod*Inv[n]%mod*Inv[n+1]%mod;a[q]=1ll*b[q]*pow(Del(1,b[q]))%mod;
const int&mid=L+R>>1;DFS1(u<<1,L,mid);DFS1(u<<1|1,mid+1,R);
}
inline void DFS2(const int&u,const int&L=1,const int&R=n){
if(L==R)return;const int&p=b[id[u]];ans=(ans+1ll*pow(Del(1,p),m)*a[id[u]])%mod;
const int&mid=L+R>>1;DFS2(u<<1,L,mid);DFS2(u<<1|1,mid+1,R);
}
signed main(){
n=read();m=read();V=read();init(max(n,m)+1<<1);
DFS1(1);if(!q)return write(0),0;f=Newton(m+2,min(V+1,m)+1);f=resize(Der(f)*inv(f>>1),m+1);
int L=m+1;
for(int a(1),b(pow(V+2)),i=0;i<L;++i){
f[i]=(1+1ll*(mod-f[i])*a)%mod*ifac[i]%mod*ifac[m-i]%mod*fac[m]%mod;a=1ll*a*b%mod;
}
if(L<q)L=q;Build(1);G[1]=timesT(resize(f,L),inv(resize(F[1],L)),q);Solve(1);DFS2(1);write(ans);
}