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

先膜拜 zxyoi

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

首先考虑 k = 0 k=0 的情况
大力 d p 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}

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

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

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

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

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

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

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

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

扫描二维码关注公众号,回复: 8675840 查看本文章

自己拍了一下没有交

#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;
}
发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/103497716
tc