题意

用 \(m\) 种颜色,给 \(n\) 个点的无向完全图的 \(\frac{n(n-1)}{2}\) 条边染色,两种方案相同当且仅当一种方案交换一些点的编号后可以变成另一种方案。问有多少本质不同的染色方案。

\(n\le 53, m\le 1000, n<mod\le 10^9\) 且 \(mod\) 为质数。

分析

  • 考虑 \(Polya​\) 定理。
  • 假设已经枚举了一个点置换(对应唯一一种边置换),能否快速求出对应边的置换的循环个数?
  • 对于两个点的循环(设长度分别为 \(l_1,l_2\)),它们之间的边构成了 \(\frac{l_1l_2}{lcm(l_1,l_2)}=gcd(l_1,l_2)​\) 个边的循环。
  • 对于一个点循环内部的边:假设初始在序列上选定的两个点的位置相差了 \(x\) ,在右端点转回序列左端后差值会变成 \(n-x\) 。可以得到,当且仅当 \(2x=n\) 时,循环长度为 \(\frac{n}{2}\)(无向图) ,其余时刻为 \(n\) 。所以当 \(n\) 为偶数时的边循环个数还要加 1。由于总边数为 \(\frac{n(n-1)}{2}\) ,所以边循环个数总可以写成 \(\lfloor\frac{n}{2}\rfloor​\) 的形式。
  • 那么对于一种点置换,假设其所有循环满足 \(l_1\le l_2\le \cdots\le l_k\) ,这样的置换个数为 \(\frac{n!}{l_1l_2\cdots l_kS_1!S_2!\cdots S_{max}!}\) ,其中 \(S_i\) 表示长度为 \(i\) 的循环个数。为什么是 \(l_i\) 而不是 \(l_i!\) 的原因是每次我们找 \(l_i\) 个位置作为一个循环之后,他们都连了一条指向其他位置的边,构成了一个环。环排列的个数是 \(\frac{n!}{n}=(n-1)!\) 。
  • 综上,对于一种点置换,对应边置换的循环个数为 \(\sum_{i=1}^k\lfloor\frac{l_i}{2}\rfloor+\sum_{i=1}^{k-1}\sum_{j=i+1}^kgcd(l_i,l_j)\) 。
  • 由于 \(n\le 53\) ,拆分的方案数在一个可接受的范围内。所以爆搜循环的拆分即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 60;
int n, m, mod;
LL fac[N], invfac[N], inv[N], ans;
int g[N][N], stk[N], num[N];
LL Pow(LL a, LL b) {
LL res = 1ll;
for(; b; b >>= 1, a = a * a % mod) if(b & 1) res = res * a % mod;
return res;
}
void add(LL &a, LL b) {
a += b;
if(a >= mod) a -= mod;
}
void solve( int tp) {
re(num);
rep(i, 1, tp) num[stk[i]]++;
LL cnt = fac[n];
rep(i, 1, tp) cnt = cnt * inv[stk[i]] % mod;
rep(i, 1, n) cnt = cnt * invfac[num[i]] % mod;
LL c = 0;
rep(i, 1, tp) c = (c + stk[i] / 2) % (mod - 1);
rep(i, 1, tp - 1)
rep(j, i + 1, tp) c = (c + g[stk[i]][stk[j]]) % (mod - 1);
add(ans, cnt * Pow(m, c) % mod);
}
void dfs(int dep, int rest, int lst) {
if(!rest) {
solve(dep - 1);
return;
}
for(int i = lst; i <= rest; ++i) stk[dep] = i, dfs(dep + 1, rest - i, i);
}
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
}
int main() {
n = gi(), m = gi(), mod = gi();
rep(i, 0, n)
rep(j, 0, n) g[i][j] = gcd(i, j);
inv[1] = fac[0] = invfac[0] = 1;
rep(i, 1, n) {
if(i ^ 1) inv[i] = (LL) (mod - mod / i) *inv[mod % i] % mod;
fac[i] = (LL) fac[i - 1] * i % mod;
invfac[i] = (LL) invfac[i - 1] * inv[i] % mod;
}
inv[0] = 1;
dfs(1, n, 1);
printf("%lld\n", ans * invfac[n] % mod);
return 0;
}

[SHOI2006]color 有色图[群论、组合计数]的更多相关文章

  1. bzoj 1815: [Shoi2006]color 有色图 置换群

    1815: [Shoi2006]color 有色图 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 136  Solved: 50[Submit][Stat ...

  2. BZOJ1815: [Shoi2006]color 有色图

    BZOJ1815: [Shoi2006]color 有色图 Description Input 输入三个整数N,M,P 1< = N <= 53 1< = M < = 1000 ...

  3. BZOJ 1815: [Shoi2006]color 有色图(Polya定理)

    题意 如果一张无向完全图(完全图就是任意两个不同的顶点之间有且仅有一条边相连)的每条边都被染成了一种颜色,我们就称这种图为有色图. 如果两张有色图有相同数量的顶点,而且经过某种顶点编号的重排,能够使得 ...

  4. BZOJ 1815: [Shoi2006]color 有色图 [Polya DFS 重复合并]

    传送门 题意: 染色图是无向完全图,且每条边可被染成k种颜色中的一种.两个染色图是同构的,当且仅当可以改变一个图的顶点的编号,使得两个染色图完全相同.问N个顶点,k种颜色,本质不同的染色图个数(模质数 ...

  5. bzoj 1478: Sgu282 Isomorphism && 1815: [Shoi2006]color 有色图【dfs+polya定理】

    参考 https://wenku.baidu.com/view/fee9e9b9bceb19e8b8f6ba7a.html?from=search### 的最后一道例题 首先无向完全图是个若干点的置换 ...

  6. bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...

  7. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  8. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  9. 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)

    [HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...

随机推荐

  1. Android 自定义弹出框带EditText

    EditText 布局页面 edittext_ownername_dialog.xml: <?xml version="1.0" encoding="utf-8&q ...

  2. (转载)解决NVIDIA显卡驱动“没有找到兼容的图形硬件”的问题

    (转载)解决NVIDIA显卡驱动“没有找到兼容的图形硬件”的问题 原出处:http://www.cnblogs.com/longdouhzt/archive/2012/02/28/2370660.ht ...

  3. ansible部署 lnmp+wordpress

    如上,是项目的目录结构. common: 获取阿里云的yum源 mysql: 二进制安装mysql nginx: 编译安装nginx php-fpm:编译安装php-fpm wordpress: 获取 ...

  4. redis搭建主从(1主2从)

    一,先附上配置文件 1,master(6379.conf)上面的配置文件 daemonize yes pidfile /usr/local/redis/logs/redis_6379.pid port ...

  5. ConcurrentDictionary与Dictionary 替换

    本文导读:ASP.NET中ConcurrentDictionary是.Net4 增加的,相对于Dictionary的线程安全的集合, ConcurrentDictionary可实现一个线程安全的集合, ...

  6. c# 采用datatable 快速导入数据至MSSQL的方法分享

    转自:http://www.maomao365.com/?p=5613 摘要:下文讲述使用c#代码快速将dataTable导入至mssql数据库的方法 实现思路:需要将datatable调整为同目标表 ...

  7. 洗礼灵魂,修炼python(91)-- 知识拾遗篇 —— pymysql模块之python操作mysql增删改查

    首先你得学会基本的mysql操作语句:mysql学习 其次,python要想操作mysql,靠python的内置模块是不行的,而如果通过os模块调用cmd命令虽然原理上是可以的,但是还是不太方便,那么 ...

  8. MySQL各类SQL语句的加锁机制

    官网参考:https://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html MySQL把读操作分为两大类:锁定读和非锁定读(即locking ...

  9. Lua中的#

    Lua中的 对字符串来说,#取字符串的长度,但对于table需要注意. lua的table可以用数字或字符串等作为key, #号得到的是用整数作为索引的最开始连续部分的大小, 如果t[1] == ni ...

  10. 更换jupyter notebook风格主题、修改默认工作路径(Ubuntu系统和Win系统)

    默认的风格对代码关键词的颜色提醒很不明显,而且白色背景长久使用非常刺眼,所以考虑更换主题. 在更换途中,发现代码输出行,前几个字符被遮挡显示不出来,找了很久才解决,备忘一些要点. 1:替换主题方法 h ...