Description
初始有n个点,任意两个点之间有一条无向边,现在要移除一些无向边(至少一条),问移除后有恰好m个连通块的方案数是多少。
两个方案不同当且仅当存在至少一条无向边在某个方案中被移除,但是在另一个方案中没被移除。
答案可能很大请模一个998,244,353。
Input
第一行读入n,m。
1<=m<=n<=500
Output
第一行输出方案数。
Solution
我好弱啊,算法马拉松只会这题,还T了
首先讲一下怎么做m=1的情况
考虑容斥。设 f[i][1] 表示任意i个点形成了1个连通块的方案数,那么 f[i][1]=2i∗(i−1)2−∑Ci−1j−1∗(i−j)∗(i−j−1)2∗f[j][1] 其中j是我们枚举的1所在连通块的size,每次用总的方案减去不合法的方案,即可以任意从i-1个剩下点中拉j-1个点与1相连,然后剩下的随便连
类似的, f[i][j]=∑Ci−1k−1∗f[i−k][j−1]∗f[k][1] k表示枚举的1所在连通块的size
这里的组合数最好打杨辉三角形的表不然容易T
考虑到题目中提到的至少删一条边,我们要在m=1时去掉完全图的方案
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define ll long long
#define N 505
#define M 224751
#define MOD 998244353
ll f[N][N],c[N][N],jc[M];
int n,m;
void init() {
rep(i,0,n) {
c[i][0]=1;
rep(j,1,i) {
c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
}
}
int lim=c[n][2];
jc[0]=1;
rep(i,1,lim) jc[i]=(jc[i-1]+jc[i-1])%MOD;
}
ll ksm(ll x,ll dep) {
ll ret=1;
for (;dep;dep>>=1,x=x*x%MOD) {
if (dep&1) {
ret=ret*x%MOD;
}
}
return ret;
}
int main(void) {
scanf("%d%d",&n,&m);
init();
f[1][1]=1;
ll tmp=0;
rep(i,2,n) {
f[i][1]=jc[c[i][2]];
rep(j,1,i-1) {
tmp=c[i-1][j-1];
f[i][1]=(f[i][1]+MOD-c[i-1][j-1]*jc[c[i-j][2]]%MOD*f[j][1]%MOD)%MOD;
}
}
rep(j,2,m) {
rep(i,j,n) {
rep(k,1,i-1) {
f[i][j]=(f[i][j]+c[i-1][k-1]*f[i-k][j-1]%MOD*f[k][1]%MOD)%MOD;
}
}
}
if (m==1) {
f[n][m]+=MOD-1;
f[n][m]%=MOD;
}
printf("%lld\n",f[n][m]);
return 0;
}