題目連接c++
一類樹(連出的邊數集合必定)的貢獻
\[ \mathbb{Ans}(\{d_n\}|\sum_id_i=2(n-1))=\prod_ia_i^{d_i}\prod_id_i^m\sum_{i}d_i^m \]
引入Prufer序列,設\(d_i\)爲點(聯通塊)在序列中出現的次數,轉換
\[ \begin{aligned} \mathbb{Ans}(\{d_n\}|\sum_{i}d_i=n-2) &=\prod_ia_i^{d_i+1}\prod_i{(d_i+1)^m}\sum_{i}(d_i+1)^m\\ &=\prod_ia_i^{d_i+1}(d_i+1)^m\sum_{i}(d_i+1)^m\\ \end{aligned} \]
那麼枚舉全部的Prufer的組合,總答案
\[ \begin{aligned} \mathbb{Ans} &=\sum_{\sum_id_i=n-2}\frac{(n-2)!}{\prod_id_i!}\prod_ia_i^{d_i+1}(d_i+1)^m\sum_{i}(d_i+1)^m\\ &=(n-2)!\prod_ia_i\sum_{\sum_id_i=n-2}\prod_i\frac{a_i^{d_i}(d_i+1)^m}{d_i!}\sum_i(d_i+1)^{m}\\ &=(n-2)!\prod_ia_i(\sum_{\sum_id_i=n-2}\sum_i\frac{a_i^{d_i}(d_i+1)^{2m}}{d_i!}\prod_{i\not=j}\frac{a_j^{d_i}(d_j+1)^m}{a_j!}) \end{aligned} \]
G8麻煩……請出生成函數
\[ A(x)=\sum_i\frac{x^i(i+1)^{2m}}{i!}\\ B(x)=\sum_i\frac{x^i(i+1)^m}{i!}\\ F(x)=\sum_iA(a_ix)\prod_{i\not=j}B(a_jx) \]
注意到\([n-2]F(x)\)正是\(\mathbb{Ans}\)中很是數部分(括號註明部分)。因而須要處理\(F(x)\)
\[ F(x)=\sum_i\frac{A(a_ix)}{B(a_ix)}\prod_{i}B(a_ix)=\sum_i\frac{A(a_ix)}{B(a_ix)}\exp(\sum_{i}\ln(B(a_ix))) \]
在\(\ln\exp\)中視\(a_ix\)總體爲變量,處理\(\frac{A(x)}{B(x)}\)和\(\ln(B(x))\)的係數,再用\(a_ix\)代換\(x\),求出\(\sum\frac{A(a_ix)}{B(a_ix)}\)以及\(\sum\ln(B(a_ix))\)。數組
這兩個過程本質相同:和函數\(\sum\)的第\(i\)向係數是單個函數的\(i\)項係數(常量)乘上\(\sum_ka_k^i\)。函數
因而涉及到一個序列的冪和,它的生成函數
\[ f(x)=\sum_i\sum_ja_j^ix^i=\sum_i\sum_j(a_ix)^j=\sum_i\frac{1}{1-a_ix}\\ g(x)=\sum_i\ln(\frac{1}{1-a_ix})=\sum_i\frac{-a_i}{1-a_ix}=-\sum_i\sum_ja_i^{j+1}x^j\\ f(x)=n-x\times g(x)\\ g(x)=\sum_i\ln((1-a_ix)^{-1})=-\ln(\prod_i1-a_ix) \]
關於這個\(\ln\)視\(x\)爲變量而非\(a_ix\),因而分治FFT處理\(g(x)\),設\(L\)爲不小於\(n\)的2的冪,能夠粗略的估計爲複雜度
\[ \sum_d^{\log L}\frac{L}dd\log d=L\sum_d^{\log L}\log d=L\log(\log(L)!) \]
打表發現\(\log(\log(L)!)\)較\(\log(L)\)略大,遠小於\(\log^2\)所在規模,因而近似認爲複雜度爲\(O(n\log n)\)ui
最後慢慢推回去……spa
有不少波折……目前洛谷rank1code
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=200000; const int MOD=998244353; inline int qpow(int x,int y) { int c=1; for(; y; y>>=1,x=(ll)x*x%MOD) if(y&1) c=(ll)c*x%MOD; return c; } //------- POLYNOMIAL BEGIN ------- int w[N],rev[N],_inv[N],lmt; inline void preDone(int len) { int l=0; lmt=1; _inv[1]=1; while(lmt<=len) lmt<<=1,l++; for(int i=0; i<lmt; ++i) { rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1)); if(i>1) _inv[i]=(ll)_inv[MOD%i]*(MOD-MOD/i)%MOD; } int wlmt=qpow(3,(MOD-1)>>l),tmp=lmt>>1; w[tmp]=1; for(int i=tmp+1; i<lmt; ++i) w[i]=(ll)w[i-1]*wlmt%MOD; for(int i=tmp-1; i>0; --i) w[i]=w[i<<1]; lmt=l; } inline void DFT(int a[],int len) { static unsigned long long tmp[N]; int u=lmt-__builtin_ctz(len),T; for(int i=0; i<len; ++i) tmp[rev[i]>>u]=a[i]; for(int m=1; m<len; m<<=1) for(int i=0,s=m<<1; i<len; i+=s) for(int j=0; j<m; ++j) T=tmp[i+j+m]*w[m+j]%MOD,tmp[i+j+m]=tmp[i+j]+MOD-T,tmp[i+j]+=T; for(int i=0; i<len; ++i) a[i]=tmp[i]%MOD; } inline void IDFT(int a[],int len) { reverse(a+1,a+len); DFT(a,len); ll T=MOD-(MOD-1)/len; for(int i=0; i<len; ++i) a[i]=T*a[i]%MOD; } inline int getLen(int len) { return 1<<(32-__builtin_clz(len)); } inline void getDer(int a[],int b[],int n) { for(int i=0; i<n-1; ++i) b[i]=(ll)(i+1)*a[i+1]%MOD; b[n-1]=0; } inline void getInt(int a[],int b[],int n) { for(int i=n-1; i>0; --i) b[i]=(ll)_inv[i]*a[i-1]%MOD; b[0]=0; } inline void getInv(int a[],int b[],int n) { static int tmp[N]; if(n==1) {b[0]=qpow(a[0],MOD-2); return;} getInv(a,b,(n+1)>>1); int len=getLen(n<<1); for(int i=0; i<n; ++i) tmp[i]=a[i]; for(int i=n; i<len; ++i) tmp[i]=0; DFT(tmp,len); DFT(b,len); for(int i=0; i<len; ++i) b[i]=(ll)b[i]*(2+MOD-(ll)b[i]*tmp[i]%MOD)%MOD; IDFT(b,len); for(int i=n; i<len; ++i) b[i]=0; } inline void getLn(int a[],int b[],int n) { static int tmp[N]; getInv(a,tmp,n); getDer(a,b,n); int len=getLen(n<<1); DFT(tmp,len); DFT(b,len); for(int i=0; i<len; ++i) tmp[i]=(ll)b[i]*tmp[i]%MOD; IDFT(tmp,len); getInt(tmp,b,n); for(int i=n; i<len; ++i) b[i]=0; for(int i=0; i<len; ++i) tmp[i]=0; } inline void getExp(int a[],int b[],int n) { static int tmp[N]; if(n==1) {b[0]=1; return;} getExp(a,b,(n+1)>>1); getLn(b,tmp,n); int len=getLen(n<<1); for(int i=0; i<n; ++i) tmp[i]=((i==0)+MOD-tmp[i]+a[i])%MOD; for(int i=n; i<len; ++i) tmp[i]=0; DFT(tmp,len); DFT(b,len); for(int i=0; i<len; ++i) b[i]=(ll)tmp[i]*b[i]%MOD; IDFT(b,len); for(int i=n; i<len; ++i) b[i]=0; for(int i=0; i<len; ++i) tmp[i]=0; } //------- POLYNOMIAL END ------- int n,m,con,a[N],d[20][N]; void solve(int l,int r,int p) { if(l==r) { d[p][0]=1; d[p][1]=MOD-a[l]; return; } int mid=(l+r)>>1; solve(l,mid,p); solve(mid+1,r,p+1); int len=getLen(r-l+1); for(int i=mid-l+2; i<len; ++i) d[p][i]=0; for(int i=r-mid+1; i<len; ++i) d[p+1][i]=0; DFT(d[p],len); DFT(d[p+1],len); for(int i=0; i<len; ++i) d[p][i]=(ll)d[p][i]*d[p+1][i]%MOD; IDFT(d[p],len); } int fc[N],fv[N]; int S[N],A[N],B[N],P[N],Q[N]; int main() { //freopen("filename.in","r",stdin); fc[0]=fc[1]=fv[0]=fv[1]=1; for(int i=2; i<N; ++i) fv[i]=(ll)fv[MOD%i]*(MOD-MOD/i)%MOD; for(int i=2; i<N; ++i) fv[i]=(ll)fv[i-1]*fv[i]%MOD; for(int i=2; i<N; ++i) fc[i]=(ll)fc[i-1]*i%MOD; scanf("%d%d",&n,&m); preDone((n+1)*4); con=fc[n-2]; for(int i=1; i<=n; ++i) scanf("%d",a+i),con=(ll)con*a[i]%MOD; solve(1,n,0); getLn(d[0],S,getLen(n)); //改爲二的冪次彷佛能緩解數組清空問題…… S[0]=n; for(int i=1; i<=n; ++i) S[i]=(MOD-(ll)S[i]*i%MOD)%MOD; for(int i=0; i<=n-2; ++i) { A[i]=(ll)fv[i]*qpow(i+1,2*m)%MOD; B[i]=(ll)fv[i]*qpow(i+1,m)%MOD; } getInv(B,P,n-1); getLn(B,Q,n-1); int len=getLen(n<<1); DFT(A,len); DFT(P,len); for(int i=0; i<len; ++i) P[i]=(ll)A[i]*P[i]%MOD; IDFT(P,len); for(int i=n-1; i<len; ++i) P[i]=0; for(int i=0; i<=n-2; ++i) { P[i]=(ll)P[i]*S[i]%MOD; Q[i]=(ll)Q[i]*S[i]%MOD; } memset(B,0,sizeof B); //這兒也是…… getExp(Q,B,n-1); DFT(P,len); DFT(B,len); for(int i=0; i<len; ++i) P[i]=(ll)P[i]*B[i]%MOD; IDFT(P,len); printf("%lld\n",(ll)con*P[n-2]%MOD); return 0; }