題目描述:
圖中有 個連通塊,每個連通塊有 個點,需要再連 條邊,使其變成一棵樹。
對一種連邊方案,設原圖中第 個連通塊連出了 條邊,那麼這棵樹 的價值爲
求所有生成樹的價值和,模
題目分析:
補充一下怎麼求等冪和
-
方法一
分母用分治NTT求出,考慮分母的 項的係數,它是在 個單項式裏面選 個取 乘起來得到的
而對於分子的 項的係數,它是在刪去一個單項式後選 個取 乘起來再求和得到的。
考慮某 個取 的單項式,它在分母中被算了一次,在分子中被算了 次,所以分子的 項係數等於分母的 項係數乘以 -
方法二
考慮用對數把的求和改爲求積:
,那麼就只需要求
分治NTT後求 即可。
Code(發現用vector寫LN和EXP意外的好寫 雖然要寫個Mul函數 ):
#include<bits/stdc++.h>
#define maxn 70005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
using namespace std;
const int mod = 998244353;
int w[maxn],WL,r[maxn],fac[maxn],inv[maxn],invf[maxn],lg[maxn];
int Pow(int a,int b){int s=1;for(;b;b>>=1,a=1ll*a*a%mod) b&1&&(s=1ll*s*a%mod);return s;}
void init(int n){
w[0]=WL=1; while(WL<=n) WL<<=1; w[1]=Pow(3,(mod-1)/WL);
for(int i=2;i<=WL;i++) w[i]=1ll*w[i-1]*w[1]%mod,lg[i]=lg[i>>1]+1;
inv[0]=inv[1]=invf[0]=invf[1]=fac[0]=fac[1]=1;
for(int i=2;i<=WL;i++) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,invf[i]=1ll*invf[i-1]*inv[i]%mod;
}
int upd(int x){return x+(x>>31&mod);}
void NTT(int *a,int len,int flg){
for(int i=0;i<len;i++) if(i<(r[i]=r[i>>1]>>1|(i&1?len>>1:0))) swap(a[i],a[r[i]]);
for(int i=2,l=1,v;i<=len;l=i,i<<=1) for(int j=0,t=WL/i;j<len;j+=i) for(int k=j,o=0;k<j+l;k++,o+=t)
a[k+l]=upd(a[k]-(v=1ll*w[flg^1?WL-o:o]*a[k+l]%mod)),a[k]=upd(a[k]+v-mod);
if(flg^1) for(int i=0,Inv=mod-(mod-1)/len;i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
typedef vector<int> Poly;
Poly Mul(const Poly &A,const Poly &B){
static int a[maxn],b[maxn]; int n=A.size(),m=B.size(),L=1<<lg[n+m-2]+1;
if(n<=20||m<=20||n+m<=200) {rep(i,0,n+m-2) a[i]=0; rep(i,0,n-1) rep(j,0,m-1) a[i+j]=(a[i+j]+1ll*A[i]*B[j])%mod;}
else{
for(int i=0;i<L;i++) a[i]=i<n?A[i]:0,b[i]=i<m?B[i]:0;
NTT(a,L,1),NTT(b,L,1); rep(i,0,L-1) a[i]=1ll*a[i]*b[i]%mod; NTT(a,L,-1);
}
return Poly(a,a+n+m-1);
}
Poly INV(const Poly &A,int n){
static int B[maxn],a[maxn]; B[B[1]=0]=Pow(A[0],mod-2);
for(int k=2,L=4;k<n<<1;k=L,L<<=1){
memcpy(a,&A[0],min(n,k)<<2); rep(i,k,L-1) a[i]=B[i]=0;
NTT(a,L,1),NTT(B,L,1); rep(i,0,L-1) B[i]=1ll*B[i]*upd(2-1ll*a[i]*B[i]%mod)%mod; NTT(B,L,-1);
memset(B+k,0,k<<2);
}
return Poly(B,B+n);
}
Poly LN(const Poly &A,int n){
Poly a(n-1),b(INV(A,n));
rep(i,0,n-2) a[i]=1ll*A[i+1]*(i+1)%mod;
a=Mul(a,b),b[0]=0;
rep(i,1,n-1) b[i]=1ll*a[i-1]*inv[i]%mod;
return b;
}
Poly EXP(const Poly &A,int n){
Poly B{1},b;
for(int k=2,L=4;k<n<<1;k=L,L<<=1){
B.resize(k),b=LN(B,k); rep(i,0,min(n,k)-1) b[i]=upd((i==0)-b[i]+A[i]);
B=Mul(B,b),B.resize(min(n,k));
}
return B;
}
int a[maxn];
Poly solve(int l,int r){
if(l==r) return {1,mod-a[l]};
int mid=(l+r)>>1;
return Mul(solve(l,mid),solve(mid+1,r));
}
int n,m;
int main()
{
scanf("%d%d",&n,&m),init(2*n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
Poly A(solve(1,n)),B(n-1);
rep(i,0,n-2) B[i]=1ll*(n-i)*A[i]%mod; A=Mul(B,INV(A,n-1));
Poly F(n-1); rep(i,0,n-2) F[i]=1ll*invf[i]*Pow(i+1,m)%mod;
Poly PF(LN(F,n-1)); rep(i,0,n-2) PF[i]=1ll*PF[i]*A[i]%mod; PF=EXP(PF,n-1);
Poly SF(n-1); rep(i,0,n-2) SF[i]=1ll*invf[i]*Pow(i+1,2*m)%mod;
SF=Mul(SF,INV(F,n-1)); rep(i,0,n-2) SF[i]=1ll*SF[i]*A[i]%mod; SF.resize(n-1);
int prd=1; rep(i,1,n) prd=1ll*prd*a[i]%mod;
printf("%d\n",1ll*prd*fac[n-2]%mod*(Mul(PF,SF)[n-2])%mod);
}