51nod1835 完全图 容斥+dp

来源:互联网 发布:天津网络教育大学 编辑:程序博客网 时间:2024/06/10 23:51

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(i1)2Ci1j1(ij)(ij1)2f[j][1] 其中j是我们枚举的1所在连通块的size,每次用总的方案减去不合法的方案,即可以任意从i-1个剩下点中拉j-1个点与1相连,然后剩下的随便连

类似的,f[i][j]=Ci1k1f[ik][j1]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 998244353ll 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;}
原创粉丝点击