【题解】CodeChef - TREDEG (prufer+生成函数+多项式exp)
好毒瘤的数据范围...
先转prufer,现在问题就变成了我要生成一个\(n-2\)长度的序列,每一种序列的权值定义为每种数的\(\prod\)(每种数出现个数+1),可以直接使用指数型生成函数生成,具体的:
\[ (\sum_{i=0} {i+1\over i!}x^i)^n[x^{n-2}](n-2)! \]
这个就生成这个序列的答案了。用exp搞个快速幂就完事了。
最终答案的式子
\[ (\sum_{i=0} {i+1\over i!}x^i)^n[x^{n-2}](n-2)!\over n^{n-2} \]
然后数据范围要我们单独做\(k=1\),那么把\((\sum_{i=0} {i+1\over i!}x^i)^n[x^{n-2}]\)单独拿出来
\[ (\sum_{i=0} {i+1\over i!}x^i)^n[x^{n-2}] \]
用\(e^x\)代替
\[ (xe^x+e^x)^n[x^{n-2}] \]
二项式定理展开
\[ [x^{n-2}]\sum {n\choose i} x^ie^{ix}e^{(n-i)x} \]
合并
\[ [x^{n-2}]\sum {n\choose i} x^ie^{nx} \]
化简一下
\[ \sum {n\choose i} e^{nx}[x^{n-2-i}] \]
泰勒展开一下
\[ \sum {n\choose i} {n^{n-2-i}\over (n-2-i)!} \]
就可以\(O(n)\)算了。
代码:(很长)
//@winlere
#include
#include
#include
#include
//#define getchar() (__c==__ed?(__ed=__buf+fread(__c=__buf,1,1<<18,stdin),*__c++):*__c++)
using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c)) f|=c==45,c=getchar();
while( isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1<<22;
const int mod=998244353;
const int g=3;
const int gi=(mod+1)/3;
inline int MOD(const int&x){return x>=mod?x-mod:x;}
inline int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
int invs[maxn],jc[maxn],inv[maxn];
int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba;t;t>>=1,b=MOD(b,b))
if(t&1) ret=MOD(ret,b);
return ret;
}
void NTT(int*a,const int&len,const int&tag){
static int r[maxn];
for(int t=1;t>1]>>1|(t&1?len>>1:0))>t)
swap(a[t],a[r[t]]);
for(int t=1,s=tag==1?g:gi,wn;t>1);
static int A[maxn],B[maxn];
memset(A,0,len<<3); memset(B,0,len<<3);
memcpy(A,a,len<<2); memcpy(B,b,len<<2);
NTT(A,len<<1,1); NTT(B,len<<1,1);
for(int t=0;t>1);
static int A[maxn],B[maxn];
memset(A,0,len<<3); memset(B,0,len<<3);
memcpy(A,b,len<<1); LN(b,B,len);
for(int t=0;t