置换群是弱项.
Description
$n$个点, 本质不同的完全图有多少个.
Solution
可以把$n \choose 2$的每条边视为黑/白, 也就是给完全图做染色了.
但本题的同构定义在点的置换上, 我们需要做一些转化.
考虑一个长为$x$的点循环节, 再考虑一条边, 如果两端都在这个循环节里, 那么这条边经过$x$轮就会回到原处(不考虑对称轴). 也就是一个循环途径了$x$条边.
所以这样产生的边循环节有$\frac{x \choose 2}{x}$个. 大概是$\frac{2}{x}$. 偶数循环还要讨论一下对称轴.
然后考虑一下不在同一循环节内的边是怎么被置换的, 一条横跨两个循环节的边, 一定经过$lcm(x,y)$轮回到开始, 对于所有横跨这两个循环节的边来说, 就有$\frac{xy}{lcm(x,y)}$个边循环节了, 也就是$gcd(x,y)$.
根据Polya就有本质不同的染色方案$\frac{1}{N!}\sum{2^{m}}$, 其中$m$是每种置换的边循环节个数.
我们有点置换和边置换是一一对应的, 所以用枚举点置换的方法(枚举拆分)就可以算了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include <bits/stdc++.h> #define mod 997
using namespace std;
const int maxn = 61;
typedef long long ll;
int n; int val[maxn], num[maxn], cnt; ll fac[maxn], ans, inv[maxn], facinv[maxn], bin[maxn];
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } void init() { fac[0] = fac[1] = 1; inv[1] = 1; facinv[0] = facinv[1] = 1; for (int i = 2; i <= n; ++i) { fac[i] = (fac[i - 1] * i) % mod; inv[i] = inv[mod % i] * (mod - mod / i) % mod; facinv[i] = facinv[i - 1] * inv[i] % mod; } } inline ll quick_power(ll base, ll index) { ll ret = 1; while (index) { if (index & 1) ret = ret * base % mod; index >>= 1; base = base * base % mod; } return ret; } void dfs(int curNum, int left) { if (!left) { ll loopCount = 0, permCount = 1; for (int i = 1; i <= cnt; ++i) { loopCount += (num[i] * (num[i] - 1) / 2 * val[i]) + (val[i] / 2 * num[i]); for (int j = i + 1; j <= cnt; ++j) { loopCount += num[i] * num[j] * gcd(val[i], val[j]); } } for (int i = 1; i <= cnt; ++i) { permCount = permCount * quick_power(val[i], num[i]) % mod * fac[num[i]] % mod; } permCount = quick_power(permCount, mod - 2) * fac[n] % mod; ans = (ans + quick_power(2, loopCount) * permCount % mod) % mod; return; } if (curNum > left) return; dfs(curNum + 1, left); for (int i = 1; i * curNum <= left; ++i) { val[++cnt] = curNum; num[cnt] = i; dfs(curNum + 1, left - i * curNum); --cnt; } }
int main() { scanf("%d", &n); init(); dfs(1, n); ans = ans * facinv[n] % mod; printf("%lld\n", ans); return 0; }
|