【TC 12104】KingdomAndCities(组合数学)(分类讨论)

先膜拜 zxyoi

题意:求 n ≤ 50 n\le 50 n50 个点 m ≤ 50 m\le 50 m50 条边
k ≤ 2 k\le 2 k2 个点的度数只能是 2 的带标号无向图个数

首先考虑 k = 0 k=0 k=0 的情况
大力 d p dp dp 容斥转移
f [ n ] [ m ] = ( ( n 2 ) m ) − ∑ i = 1 n − 1 ( n − 1 i − 1 ) ∑ j = 1 m f [ i ] [ j ] ∗ ( ( n − i 2 ) m − j ) f[n][m]=\binom{\binom{n}{2}}{m}-\sum_{i=1}^{n-1}\binom{n-1}{i-1}\sum_{j=1}^mf[i][j]*\binom{\binom{n-i}{2}}{m-j} f[n][m]=(m(2n))i=1n1(i1n1)j=1mf[i][j](mj(2ni))

k = 1 k=1 k=1,考虑先把一个图填好,然后随便选一条边把这个点插进去

发现需要分放进去的点在不在三元环中讨论
不在的话就多了一个点一条边, ( m − 1 ) f [ n − 1 ] [ m − 1 ] (m-1)f[n-1][m-1] (m1)f[n1][m1]
否则多了一个点两条边, ( m − 2 ) f [ n − 1 ] [ m − 2 ] (m-2)f[n-1][m-2] (m2)f[n1][m2]

k = 2 k=2 k=2
分两个点有没有捆绑讨论:
没有捆绑:

两个点都在 3 元环中,发现可以有公共边
两个的填发不冲突, ( m − 4 ) 2 f [ n − 2 ] [ m − 4 ] (m-4)^2f[n-2][m-4] (m4)2f[n2][m4]

一个点在 3 元环,一个点不在, 2 ∗ ( m − 3 ) ∗ ( m − 4 ) ∗ f [ n − 2 ] [ m − 3 ] 2*(m-3)*(m-4)*f[n-2][m-3] 2(m3)(m4)f[n2][m3]

两个点都不在:
需要分有没有形成 4 元环讨论,如果形成了就是 ( m − 3 ) f [ n − 2 ] [ m − 3 ] (m-3)f[n-2][m-3] (m3)f[n2][m3]
如果没有就是 ( m − 2 ) ∗ ( m − 3 ) ∗ f [ n − 2 ] [ m − 2 ] (m-2)*(m-3)*f[n-2][m-2] (m2)(m3)f[n2][m2]

两个点捆绑:
捆绑插到一条边中,发现需要分有没有形成 4 元环讨论
如果没有形成那么为 2 ∗ ( m − 2 ) ∗ f [ n − 2 ] [ m − 2 ] 2*(m-2)*f[n-2][m-2] 2(m2)f[n2][m2],注意两个点交换不同构
如果形成了就是 2 ∗ ( m − 3 ) ∗ f [ n − 2 ] [ m − 3 ] 2*(m-3)*f[n-2][m-3] 2(m3)f[n2][m3]

两个点连到同一个点上,交换同构, ( n − 2 ) ∗ f [ n − 2 ] [ m − 3 ] (n-2)*f[n-2][m-3] (n2)f[n2][m3]


自己拍了一下没有交

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 50, M = N*N;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
void Dec(int &a, int b){ a = dec(a, b); }
int C2(int n){ return n * (n-1) / 2; }
int n, m, k, c[M][M], f[N][N];
void prework(){
	int up = C2(n); c[0][0] = 1;
	for(int i = 1; i <= up; i++){
	c[i][0] = 1; for(int j = 1; j <= i; j++) c[i][j] = add(c[i-1][j], c[i-1][j-1]);
	}
	for(int i = 1; i <= n; i++)
	for(int j = i-1; j <= min(m,C2(i)); j++){
		f[i][j] = c[C2(i)][j];
		for(int p = 1; p < i; p++){
			int coef = c[i - 1][p - 1];
			for(int q = p-1; q <= min(j,C2(p)); q++)
			Dec(f[i][j], mul(f[p][q], mul(coef, c[C2(i-p)][j-q])));
		}
	}
}
int F(int n, int m){ if(n<0||m<0) return 0; return f[n][m]; }
int main(){
	cin >> n >> k >> m; 
	prework(); 
	if(n == 1){ if(!m && !k) puts("1"); else puts("0"); }
	if(n == 2){ if(m == 1 && !k) puts("1"); else puts("0"); }
	if(k == 0) cout << f[n][m] << '\n';
	if(k == 1) cout << add(mul(m-1,F(n-1,m-1)), mul(m-2,F(n-1,m-2))) << '\n';
	if(k == 2){
		int ans = 0;
		Add(ans, mul(mul(m-4,m-4), F(n-2,m-4)));
		Add(ans, mul(mul(m-3,m-4), mul(2,F(n-2,m-3))));
		Add(ans, mul(mul(m-2,m-3), F(n-2,m-2)));
		Add(ans, mul(m-3, F(n-2,m-3)));
		Add(ans, mul(mul(2, m-2), F(n-2,m-2)));
		Add(ans, mul(mul(2, m-3), F(n-2,m-3)));
		Add(ans, mul(n-2, F(n-2,m-3)));
		cout << ans << '\n';
	} return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值