题解 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);
}