2025.10.17C 连通性 题解
有人让我写篇题解,那我就写吧。
下定义 \([1,n-m]\) 为特殊点,其余为普通点.
显然最终的联通块森林中,只可能有两类联通块:
- 由普通点构成的团(即无向完全图)。
- 以由特殊点构成的联通块为根,所有普通点向这个根连至少一条边。该联通块内部所有普通点之间随意连边。
只考虑第二种联通块。设 \(dp_{i,j}\) 表示目前有 \(i\) 个特殊点,\(j\) 个普通点,方案数是多少。转移为:
\[dp_{i,j}=\sum_{k=1}^i\sum_{l=0}^jdp_{i-k,j-l}\binom{i-1}{k-1}\binom jltz_k2^{\frac{l(l-1)}2}(2^k-1)^l
\]
预处理组合数,\(2^k,(2^k)^l\) 和 \(tz_i\) 即可。其中 \(tz_i\) 表示 \(i\) 个点构成一个联通块的连边方案数。为预处理它,再设 \(d_j\) 表示使 \(j\) 个点和 \(i\) 联通的方案数。转移为:
\[d_j=\sum_{k=1}^jd_{j-k}tz_k\binom{i-j+k-2}{k-1}(2^k-1)
\]
加入第一种联通块可以在统计答案的时候进行,方程式为:
\[ans=\sum_{i=0}^m\binom mif_idp_{n-m,m-i}
\]
其中 \(f_i\) 表示将 \(i\) 个点划分成若干份的方案数,转移方程式为:
\[f_i=\sum_{j=1}^if_{i-j}\binom{i-1}{j-1}
\]
时间复杂度 \(O(n^4+tn)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=105,p=1e9+7;
int t,n,m,ans,dp[N][N],C[N][N],qp[N][N],tw[N*N],tz[N],f[N];
int main(){
freopen("connect.in","r",stdin);
freopen("connect.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t,C[0][0]=dp[0][0]=tz[0]=tw[0]=f[0]=1;
for(int i=1;i<=10000;i++) tw[i]=tw[i-1]*2%p;
for(int i=1;i<=100;i++){
C[i][0]=qp[i][0]=1;
for(int j=1;j<=100;j++) qp[i][j]=qp[i][j-1]*(tw[i]-1ll)%p;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
}for(int i=1;i<=100;i++){
for(int j=1;j<i;f[++j]=0) for(int k=1;k<=j;k++)
f[j]=(f[j]+1ll*f[j-k]*tz[k]%p*C[i-j+k-2][k-1]%p*(tw[k]-1))%p;
tz[i]=f[i-1],f[0]=1,f[1]=0;
}for(int i=1;i<=100;i++) for(int j=0;j<=100-i;j++) for(int k=1;k<=i;k++) for(int l=0;l<=j;l++)
dp[i][j]=(dp[i][j]+1ll*dp[i-k][j-l]*C[i-1][k-1]%p*C[j][l]%p*tz[k]%p*tw[l*(l-1)/2]%p*qp[k][l])%p;
for(int i=1;i<=100;i++) f[i]=0;f[0]=1;
for(int i=1;i<=100;i++) for(int j=1;j<=i;j++)
f[i]=(f[i]+1ll*f[i-j]*C[i-1][j-1])%p;
while(t--){
cin>>n>>m,ans=0;
for(int i=0;i<=m;i++)
ans=(ans+1ll*C[m][i]*f[i]%p*dp[n-m][m-i])%p;
cout<<ans<<"\n";
}return 0;
}

浙公网安备 33010602011771号