【xsy1301】 原题的价值 组合数+斯特林数+FFT
题目大意:求n×2(n−1)(n−2)/22n−1∑i=0(n−1i)ik
数据范围:n≤109,k≤105,答案对998244353取模。
我们令F(n,k)=n−1∑i=0(n−1i)ik。
那么最终要输出的东西显然就是n×2(n−1)(n−2)/22F(n,k)
我们令G(n,k)=(n−1)k_2n−1−k
我们先考虑下当k=0的时候要怎么做,我们显然有:
F(n,0)=n−1∑i=0(n−1i)=2n−1
化简是根据二项式定理来的,在此不展开说了。
考虑下当k=1的时候要怎么做:
F(n,1)=n−1∑i=0(n−1i)i=n−1∑i=0(n−1)!i!(n−1−i)!i=n−1∑i=1(n−1)!(i−1)!(n−1−i)!=n−1∑i=1(n−1)!(i−1)!((n−2)−(i−1))!=(n−1)n−1∑i=1(n−2)!(i−1)!((n−2)−(i−1))!=(n−1)n−1∑i=1(n−2i−1)=(n−1)F(n−1,0)=G(n,1)
我们考虑按照k=1的化简方法来化简k=2,由于跟上文比较相似,所以可能会有不少的跳步
F(n,2)=n−1∑i=0(n−1i)i2
=n−1∑i=0(n−1)!i!(n−1−i)!i2
=(n−1)n−1∑i=1(n−2i−1)i
=(n−1)n−1∑i=1(n−2)!(i−1)!((n−2)−(i−1))!((i−1)+1)
=F(n−1,1)+(n−1)n−1∑i=1(n−2)!(i−2)!((n−3)−(i−2))!
=F(n−1,1)+(n−1)(n−2)n−1∑i=1(n−3)!(i−2)!((n−3)−(i−2))!
=F(n−1,1)+(n−1)(n−2)F(n−2,0)
=G(n,1)+G(n,2)
根据k=2的推法,我们推出了k=3和k=4的情况:
F(n,3)=G(n,1)+3G(n,2)+4G(n,3)
F(n,4)=G(n,1)+7G(n,2)+6G(n,3)+G(n,4)
诶?这不是斯特林三角形吗(证明显然,这里不证了)
于是有:
F(n,m)=m∑i=1S2(n,i)G(n,i)
G(n,1⋯k)可以在O(k)的时间复杂度内求出来,S2(n,1⋯k)可以在O(klog k)的复杂度内用FFT求出来。
完结撒花~
1 #include<bits/stdc++.h> 2 #define MOD 998244353 3 #define L long long 4 #define M (1<<18) 5 #define G 3 6 using namespace std; 7 8 L fac[M]={0},invfac[M]={0}; 9 L pow_mod(L x,L k){L ans=1;for(;k>0;k>>=1,x=x*x%MOD) if(k&1) ans=ans*x%MOD; return ans;} 10 L C(int n,int m){return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;} 11 12 void change(L a[],int n){ 13 for(int i=0,j=0;i<n-1;i++){ 14 if(i<j) swap(a[i],a[j]); 15 int k=n>>1; 16 while(j>=k) j-=k,k>>=1; 17 j+=k; 18 } 19 } 20 void NTT(L a[],int n,int on){ 21 change(a,n); 22 for(int h=2;h<=n;h<<=1){ 23 L wn=pow_mod(G,(MOD-1)/h); 24 for(int j=0;j<n;j+=h){ 25 L w=1; 26 for(int k=j;k<j+(h>>1);k++){ 27 L u=a[k],t=a[k+(h>>1)]*w%MOD; 28 a[k]=(u+t)%MOD; 29 a[k+(h>>1)]=(u-t+MOD)%MOD; 30 w=w*wn%MOD; 31 } 32 } 33 } 34 if(on==-1){ 35 reverse(a+1,a+n); 36 L INV=pow_mod(n,MOD-2); 37 for(int i=0;i<n;i++) a[i]=a[i]*INV%MOD; 38 } 39 } 40 L a[M]={0},b[M]={0},s[M]={0},nc[M]={0}; 41 42 int main(){ 43 fac[0]=1; for(int i=1;i<M;i++) fac[i]=fac[i-1]*i%MOD; 44 invfac[M-1]=pow_mod(fac[M-1],MOD-2); 45 for(int i=M-2;~i;i--) invfac[i]=invfac[i+1]*(i+1)%MOD; 46 L n,k,ans=0; cin>>n>>k; 47 if(k==0) return printf("%lld\n",n*pow_mod(2,(n-1)*n/2)%MOD); 48 for(L i=0,mul=1;i<k;i++){ 49 mul=mul*(n-i-1)%MOD; 50 nc[i+1]=mul*pow_mod(2,n-i-2)%MOD; 51 } 52 for(int i=0;i<=k;i++){ 53 a[i]=pow_mod(MOD-1,i)*invfac[i]%MOD; 54 b[i]=pow_mod(i,k)*invfac[i]%MOD; 55 } 56 int len=1; while(k*2>=len) len<<=1; 57 NTT(a,len,1); NTT(b,len,1); 58 for(int i=0;i<len;i++) s[i]=a[i]*b[i]%MOD; 59 NTT(s,len,-1); 60 for(int i=k+1;i<len;i++) s[i]=0; 61 62 for(int i=1;i<=k;i++) 63 (ans+=nc[i]*s[i])%=MOD; 64 65 cout<<ans*n%MOD*pow_mod(2,(n*(n-1)/2-(n-1)))%MOD<<endl; 66 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!