Sea题解(计数+DP)

题意

n n n个点,不超过 k k k条割边的有标号图个数。 1 ≤ n ≤ 50 , 0 ≤ k ≤ 50 1\le n\le50,0\le k\le50 1n50,0k50

题解

调得怀疑人生了,总算A了。。。

n n n个点的图个数为 e n e_n en n n n个点连通图个数为 l n l_n ln n n n个点强连通图个数为 g n g_n gn n n n个点 k k k条割边的连通图个数为 f n , k f_{n,k} fn,k,则答案可以由 f f f数组求出。

显然有
e n = 2 n ( n − 1 ) 2 l n = e n − ∑ i = 1 n − 1 ( n − 1 i − 1 ) e n − i l i e_n=2^{\frac{n(n-1)}2}\\ l_n=e_n-\sum_{i=1}^{n-1}{n-1\choose i-1}e_{n-i}l_i en=22n(n1)ln=eni=1n1(i1n1)enili
g n g_n gn需要一个辅助数组 G k , n G_{k,n} Gk,n,代表有 k k k个点,把另外 n n n个点划分成一些连通块,每个连通块向这 k k k个点连边的方案数,


G k , n = ∑ i = 1 n ( n − 1 i − 1 ) l i × i k × G k , n − i g n = l n − ∑ i = 1 n − 1 ( n − 1 i − 1 ) g i G i , n − i G_{k,n}=\sum_{i=1}^n{n-1\choose i-1}l_i\times ik\times G_{k,n-i}\\ g_n=l_n-\sum_{i=1}^{n-1}{n-1\choose i-1}g_iG_{i,n-i} Gk,n=i=1n(i1n1)li×ik×Gk,nign=lni=1n1(i1n1)giGi,ni
f n , k f_{n,k} fn,k需要一个辅助数组 F k , j , i F_{k,j,i} Fk,j,i,代表有 k + i k+i k+i个点,可以在 i i i个点之间连边或者把它们和剩下 k k k个点连边,有 j j j条割边的方案数,


f i , j = ∑ k = 1 i − 1 ( i − 1 k − 1 ) g k F k , j , i − k F k , j , i = ∑ I = 0 i ∑ J = 0 j − 1 ( i − 1 I − 1 ) f I , J × k I × F k , j − J − i , i − I f_{i,j}=\sum_{k=1}^{i-1}{i-1\choose k-1}g_kF_{k,j,i-k}\\ F_{k,j,i}=\sum_{I=0}^i\sum_{J=0}^{j-1}{i-1\choose I-1}f_{I,J}\times kI\times F_{k,j-J-i,i-I} fi,j=k=1i1(k1i1)gkFk,j,ikFk,j,i=I=0iJ=0j1(I1i1)fI,J×kI×Fk,jJi,iI

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IN inline
#define R register int
const int N=55;
const ll p=1000000007;
int n,k;
ll e[N],c[N][N],l[N],g[N],G[N][N],f[N][N],F[N][N][N],ans[N][N],S;
IN ll add(ll a,ll b){return a+b<p?a+b:a+b-p;}
IN ll sub(ll a,ll b){return a-b<0?a-b+p:a-b;}
IN ll mul(ll a,ll b){return a*b%p;}
IN ll expo(ll a,int b){
	static ll c;c=1;
	while(b){
		if(b&1)c=c*a%p;
		b>>=1; a=a*a%p;
	}
	return c;
}
int main(){
	scanf("%d%d",&n,&k);
	for(R i=1;i<=n;i++)e[i]=expo(2,(i*(i-1))>>1);
	for(R i=0;i<=n;i++)c[i][0]=1;
	for(R i=1;i<=n;i++)for(R j=1;j<=i;j++)c[i][j]=add(c[i-1][j],c[i-1][j-1]);
	for(R i=1;i<=n;i++){
		l[i]=e[i];
		for(R j=1;j<i;j++)l[i]=sub(l[i],mul(mul(c[i-1][j-1],e[i-j]),l[j]));
	}
	for(R k=1;k<=n;k++)G[k][0]=1;
	for(R k=1;k<=n;k++)for(R i=1;i<=n-k;i++)for(R j=1;j<=i;j++)
		G[k][i]=add(G[k][i],mul(mul(c[i-1][j-1],j*k),mul(l[j],G[k][i-j])));
	g[0]=1;
	for(R i=1;i<=n;i++){
		g[i]=l[i];
		for(R j=1;j<i;j++)g[i]=sub(g[i],mul(mul(c[i-1][j-1],G[j][i-j]),g[j]));
	}
	for(R i=1;i<=n;i++)F[i][0][0]=1;
	for(R i=1;i<=n;i++){
		f[i][0]=g[i];
		for(R j=1;j<i;j++)for(R k=1;k<i;k++)
			f[i][j]=add(f[i][j],mul(mul(c[i-1][k-1],g[k]),F[k][j][i-k]));
		for(R k=1;k<=n-i;k++)for(R j=0;j<i+k;j++)
			for(R I=1;I<=i;I++)for(R J=0;J<j;J++)
				F[k][j][i]=add(F[k][j][i],mul(mul( c[i-1][I-1],mul(f[I][J],k*I) ),F[k][j-J-1][i-I]));
	}
	ans[0][0]=1;
	for(R i=1;i<=n;i++)for(R j=0;j<=i;j++)
		for(R I=1;I<=i;I++)for(R J=0;J<=j;J++)ans[i][j]=add(ans[i][j],mul(c[i-1][I-1],mul(f[I][J],ans[i-I][j-J])));
	for(R i=0;i<=k;i++)S=add(S,ans[n][i]);
	printf("%lld",S);
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值