[SHOI2006]color 有色图[群论、组合计数]
题意
用 \(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 有色图[群论、组合计数]的更多相关文章
- bzoj 1815: [Shoi2006]color 有色图 置换群
1815: [Shoi2006]color 有色图 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 136 Solved: 50[Submit][Stat ...
- BZOJ1815: [Shoi2006]color 有色图
BZOJ1815: [Shoi2006]color 有色图 Description Input 输入三个整数N,M,P 1< = N <= 53 1< = M < = 1000 ...
- BZOJ 1815: [Shoi2006]color 有色图(Polya定理)
题意 如果一张无向完全图(完全图就是任意两个不同的顶点之间有且仅有一条边相连)的每条边都被染成了一种颜色,我们就称这种图为有色图. 如果两张有色图有相同数量的顶点,而且经过某种顶点编号的重排,能够使得 ...
- BZOJ 1815: [Shoi2006]color 有色图 [Polya DFS 重复合并]
传送门 题意: 染色图是无向完全图,且每条边可被染成k种颜色中的一种.两个染色图是同构的,当且仅当可以改变一个图的顶点的编号,使得两个染色图完全相同.问N个顶点,k种颜色,本质不同的染色图个数(模质数 ...
- bzoj 1478: Sgu282 Isomorphism && 1815: [Shoi2006]color 有色图【dfs+polya定理】
参考 https://wenku.baidu.com/view/fee9e9b9bceb19e8b8f6ba7a.html?from=search### 的最后一道例题 首先无向完全图是个若干点的置换 ...
- bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)
黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...
- 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是第二类斯特林 ...
- 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是第二类斯特林 ...
- 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)
[HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...
随机推荐
- 初学ubuntu之文件权限权限
今天接着做笔记,坚持学习下去. 文件权限修改命令,初学者看见这个命令之后总有些摸不着头脑,这命令里面用到了一些数字,我 自己也是,这次写一篇自己的认识.希望能够帮助到需要学习的人. 首先你可以通过 l ...
- Error in Log_event::read_log_event(): 'Event too small', data_len: 0, event_type: 0
MySQL主从复制报错如下: 2018-04-11 09:11:16 2400 [Note] Slave SQL thread initialized, starting replication in ...
- SQL Server最大内存设为0后的处置办法
故障说明: 远程调整实例内存时疏忽,将实例最大内存调整为了0,因此最大内存变成了128MB的最小值. 解决方式: 1.正常关闭SQL Server服务,如果是集群,需要先关停止集群角色防止故障转移,然 ...
- c/c++ 线性表之单向链表
c/c++ 线性表之单向链表 线性表之单向链表 不是存放在连续的内存空间,链表中的每个节点的next都指向下一个节点,最后一个节点的下一个节点是NULL. 真实的第一个节点是头节点,头节点不存放数据, ...
- Python爬虫之Urllib库的基本使用
# get请求 import urllib.request response = urllib.request.urlopen("http://www.baidu.com") pr ...
- [Hive_7] Hive 中的 DDL 操作
0. 说明 DDL(Data Definition Languages)语句:数据定义语言 这些语句定义了不同的数据段.数据库.表.列.索引等数据库对象的定义. 常用的语句关键字主要包括 create ...
- 4.10Python数据处理篇之Matplotlib系列(十)---文本的显示
目录 目录 前言 (一)中文显示 ==1.全局的设置== ==2.局部的设置== (二)文本显示 目录 前言 今天我们来学习一下文本的显示 (一)中文显示 ==1.全局的设置== (1)说明: 在ma ...
- python入门练习题
1.使用while循环输入 1 2 3 4 5 6 8 9 10 num = 1 while num<=10: if num ==7: num += 1 continue print(n ...
- Ubuntu下导入PySpark到Shell和Pycharm中(未整理)
实习后面需要用到spark,虽然之前跟了edX的spark的课程以及用spark进行machine learning,但那个环境是官方已经搭建好的,但要在自己的系统里将PySpark导入shell(或 ...
- 为什么react的组件要super(props)
https://segmentfault.com/q/1010000008340434