图的同构
题目链接:ybt金牌导航8-5-5
题目大意
问你有多少种无编号的 n 个点无环无重边的无向图。
思路
然后做完有色图和画画阴间题再做这些就好多了?
就直接是有色图的思路,不过它这个是变成边的有无。
那你可以两种看法:
把它看成是两种颜色,那就是有色图直接
m
=
2
m=2
m=2 Polya 定理搞即可。
把它就看成是用 Burnside 引理搞,那就是画画的超级无敌简化弱化版,就直接是
2
.
.
.
2^{...}
2... 搞。
(其实一样。。。)
然后直接用有色图的分类讨论也就是画画的前置分类讨论即可。
代码
#include<cstdio>
#define ll long long
#define mo 997
using namespace std;
ll n, jc[61], inv[61], invjc[61];
ll ans, l[61], c[61], mi[61], gcd[61][61];
ll GCD(ll x, ll y) {
if (!y) return x;
return GCD(y, x % y);
}
void work(int num) {
ll re = 1;
for (int i = 1; i <= num; i++)
re = re * inv[l[i]] % mo;
for (int i = 1; i <= n; i++)
re = re * invjc[c[i]] % mo;
for (int i = 1; i <= num; i++)
re = re * mi[l[i] / 2] % mo;
for (int i = 1; i <= num; i++)
for (int j = i + 1; j <= num; j++) {
re = re * mi[gcd[l[i]][l[j]]] % mo;
}
ans = (ans + re) % mo;
}
void dfs(ll num, ll els, ll L) {
if (!els) {
work(num);
return ;
}
for (int i = L; i <= els; i++) {
l[++num] = i; c[i]++;
dfs(num, els - i, i);
l[num--] = 0; c[i]--;
}
}
int main() {
scanf("%lld", &n);
jc[0] = 1; for (int i = 1; i <= n; i++) jc[i] = jc[i - 1] * i % mo;
inv[0] = inv[1] = 1; for (int i = 2; i <= n; i++) inv[i] = inv[mo % i] * (mo - mo / i) % mo;
invjc[0] = 1; for (int i = 1; i <= n; i++) invjc[i] = invjc[i - 1] * inv[i] % mo;
mi[0] = 1; for (int i = 1; i <= n; i++) mi[i] = mi[i - 1] * 2 % mo;
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) gcd[i][j] = GCD(i, j);
dfs(0, n, 1);
printf("%lld", ans);
return 0;
}