1. 程式人生 > 其它 >題解 P7265 Look At The Sky / 加強版

題解 P7265 Look At The Sky / 加強版

題目傳送門(簡單版)

題目傳送門(加強版)

更好的閱讀體驗

套路二合一……

題意簡述

\(S(n)\) 為所有大小為 \(n\) 的無向圖形成的集合,一張無向圖的連通塊集合 \(f(G)\) 為這張圖所有極大連通塊的大小形成的任意順序的序列,對所有 \(k \in [0,K]\) 求:

\[s_k=\sum\limits_{G \in S(n)} \dfrac{\sum\limits_{i=1}^{|f(G)|}f(G)_i^k}{(\sum\limits_{i=1}^{|f(G)|}f(G)_i)^k} \]

\(n,k \leq 2 \times 10^5\)

題目分析

顯然分母是 \(n^k\)

,記 \(s_k=\sum\limits_{G \in S(n)} \sum\limits_{i=1}^{|f(G)|}f(G)_i^k\)

接下來變成了求和的形式,交換和號:

\[s_k=\sum\limits_{i=1}^n i^k \sum\limits_{G \in S(n)} [i \in f(G)] \]

後面的和式與 \(k\) 無關了,記 \(f_t=\sum\limits_{G \in S(n)} [t \in f(G)]\)

\(g_t\) 為大小為 \(t\) 的無向圖個數, \(h_t\) 為大小為 \(t\) 的聯通無向圖個數,有:

\[g_t=2^{t(t-1)/2} \]

由 exp 的組合意義(或者有標號 Set 構造),設 \(\hat H(x)\)

\(\hat G(x)\) 分別為 \(h_t\)\(g_t\) 的指數型生成函式,有 \(\hat G(x)=\exp \hat H(x)\),即 \(\hat H(x)=\ln \hat G(x)\)

顯然有 \(f_t= \dbinom{n}{t} h_t g_{n-t}\),即先選取 \(t\) 個點組成聯通塊,再用剩下的 \(n-t\) 個點組成無向圖。

現在 \(f_t\) 求出來了,只需要求出 \(s_k=\sum\limits_{i=1}^n i^k f_i\)

這是一個經典問題,考慮寫出 \(s_k\) 的生成函式 \(S(x)\)

\[S(x)=\sum\limits_{k} x^k \sum\limits_{i=1}^n i^kf_i=\sum\limits_{i=1}^n f_i \sum\limits_{k} (ix)^k=\sum\limits_{i=1}^n \dfrac{f_i}{1-ix} \]

直接分治 NTT 即可,總時間複雜度 \(O(n \log^2 n+k \log k)\)

為啥簡單版這麼卡常……

程式碼

......
int n,K;
int F[N],G[N],H[N];
int lenp[N],lenq[N],tmp[N];
vector <int> P[N],Q[N];
 
void init(int o,int l,int r){
	int len=r-l+1,mid=(l+r)>>1ll;
	if(o==1) len=max(n,K);
	lenp[o]=len;
	lenq[o]=len;
	P[o].resize(2*lenp[o]+2);
	Q[o].resize(2*lenq[o]+2);
	if(l==r) return ;
	init(o<<1,l,mid);
	init(o<<1|1,mid+1,r);
}
 
void solve(int o,int l,int r){
	int len=r-l+1;
	if(l==r){
		P[o][0]=F[l];
		Q[o][0]=1,Q[o][1]=(mod-l)%mod;
		return ;
	}
	int mid=(l+r)>>1;
	solve(o<<1,l,mid);
	solve(o<<1|1,mid+1,r);
	
	NTT::solve(P[o].data(),P[o<<1].data(),Q[o<<1|1].data(),lenp[o<<1],lenq[o<<1|1]);
	NTT::solve(tmp,Q[o<<1].data(),P[o<<1|1].data(),lenq[o<<1],lenp[o<<1|1]);
	for(int i=0;i<=len;i++) P[o][i]=(P[o][i]+tmp[i])%mod;
	
	NTT::solve(Q[o].data(),Q[o<<1].data(),Q[o<<1|1].data(),lenq[o<<1],lenq[o<<1|1]); 
}

int main(){
	pre();
	cin>>n>>K;
	for(int i=0;i<=n;i++) H[i]=1ll*ksm(2,S(i))*inv[i]%mod;//求出 H(x)
	poly::Ln(G,H,n);//求出 G(x)
	for(int i=0;i<=n;i++) F[i]=1ll*G[i]*mul[i]%mod*H[n-i]%mod*mul[n-i]%mod*C(n,i)%mod;//求出 F(x)
	init(1,1,n);
	solve(1,1,n);
	INV::solve(Q[1].data(),Q[1].data(),K);
	NTT::solve(P[1].data(),P[1].data(),Q[1].data(),K,K);
	for(int k=0;k<=K;k++) printf("%lld\n",1ll*P[1][k]*ksm(n,mod-1-k)%mod);
}