[第二类斯特林数 组合计数] 省选模拟赛 2 B. 两弹一星 missile

来源:互联网 发布:股市大数据分析工具 编辑:程序博客网 时间:2024/05/16 07:09

题目大意

一张无向图的权值定义为 xk,其中 x 是图中结构为树的连通块个数。给定 n, k, 求出所有 n 个点带标号的的简单无向图的权值和,对 998244353 取模。

xi 表示树联通块 i 是否存在 , 图的权值为 (xi)m。对于某 k 个联通块,如果同时出现,那么贡献为 S(m,k)k!
fn 为 n个点的树连通图个数,直接由prufer得出
gi,j 为 i 个点 j 个树连通块的个数,通过简单 dp 求得
再将求出来的东西套入之前的斯特林数式子就可以计算答案
dp用FFT 来优化

#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;const int N=200005;const int P=998244353;const int G=3;inline ll Pow(ll a,int b){  ll ret=1;  for (;b;b>>=1,a=a*a%P)    if (b&1)      ret=ret*a%P;  return ret;}int num;int w[2][N];int R[N];inline void Init(int n){  int x=n,L=0; num=n;  while (n>>=1) L++;  for (int i=1;i<num;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));  ll g=Pow(G,(P-1)/num);  w[1][0]=w[0][0]=1;  for (int i=1;i<num;i++) w[1][i]=(ll)w[1][i-1]*g%P;  for (int i=1;i<num;i++) w[0][i]=w[1][num-i];}inline void FFT(int *a,int n,int r){  for (int i=0;i<n;i++) if (i<R[i]) swap(a[i],a[R[i]]);  for (int i=1;i<n;i<<=1)    for (int j=0;j<n;j+=(i<<1))      for (int k=0;k<i;k++){    ll x=a[j+k],y=(ll)w[r][num/(i<<1)*k]*a[j+i+k]%P;    a[j+k]=(x+y)%P; a[j+i+k]=(x+P-y)%P;      }  if (!r) for (int i=0,inv=Pow(n,P-2);i<n;i++) a[i]=(ll)a[i]*inv%P;}ll fac[N],inv[N],S[25][25];inline ll C(int n,int m){  if (n<m) return 0;  return fac[n]*inv[m]%P*inv[n-m]%P;}ll f[N],g[25][N];inline void Pre(int n,int K){  fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;  inv[1]=1; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;  inv[0]=1; for (int i=1;i<=n;i++) inv[i]=inv[i]*inv[i-1]%P;  f[1]=1; for (int i=2;i<=n;i++) f[i]=Pow(i,i-2);  S[0][0]=1;  for (int i=1;i<=K;i++){    S[i][0]=0;    for (int j=1;j<=i;j++)      S[i][j]=(S[i-1][j-1]+(ll)S[i-1][j]*j%P)%P;  }}int n,K; ll Ans;int m;int A[N],B[N];inline void Calc_G(ll *ng,ll *g){  for (int i=0;i<m;i++) A[i]=B[i]=0;  for (int i=0;i<=n;i++)    A[i]=(ll)g[i]*inv[i]%P;  for (int i=1;i<=n;i++)    B[i]=(ll)f[i]*inv[i-1]%P;  FFT(A,m,1); FFT(B,m,1);  for (int i=0;i<m;i++)    A[i]=(ll)A[i]*B[i]%P;  FFT(A,m,0);  for (int i=1;i<=n;i++)    ng[i]=(ll)A[i]*fac[i-1]%P;}int main(){  freopen("missile.in","r",stdin);  freopen("missile.out","w",stdout);  scanf("%d%d",&n,&K); Pre(n,K);  for (m=1;m<=(n<<1);m<<=1);  Init(m);  g[0][0]=1;  for (int j=1;j<=K;j++)    Calc_G(g[j],g[j-1]);  Ans=0;  for (int i=1;i<=n;i++)    for (int j=1;j<=K;j++)      (Ans+=g[j][i]*C(n,i)%P*Pow(2,C(n-i,2))%P*S[K][j]%P*fac[j]%P)%=P;  printf("%d\n",Ans);  return 0;}
0 0
原创粉丝点击