[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\)连边( ...
随机推荐
- Javac编译原理 《深入分析java web 技术内幕》第四章
javac编译的四个主要的流程: 词法分析器:将源码转换为Token流 将源代码划分成一个个Token(找出java语言中的关键字) 语法分析器:将Token流转化为语法树 将上述的一个个Token组 ...
- JHipster生成微服务架构的应用栈(二)- 认证微服务示例
本系列文章演示如何用JHipster生成一个微服务架构风格的应用栈. 环境需求:安装好JHipster开发环境的CentOS 7.4(参考这里) 应用栈名称:appstack 认证微服务: uaa 业 ...
- Scala高阶函数实践
高阶函数主要有两种:一种是将一个函数当做另外一个函数的参数(即函数参数):另外一种是返回值是函数的函数.package sparkCore/** * Created by zhen on 2018/3 ...
- PHP 生成器语法
一般你在迭代一组数据的时候,需要创建一个数据,假设数组很大,则会消耗很大性能,甚至造成内存不足. //Fatal error: Allowed memory size of 1073741824 by ...
- mysqldump 参数--lock-tables浅析
mysqldump有一个参数--lock-tables,以前对这个参数也没有详细了解过,直到上次有个网友问"参数lock-tables 是一次性锁定当前库的所有表,还是锁定当前导出表?&qu ...
- Navicat Premium 连接oracle ORA-01017:用户名/口令无效;登陆被拒绝
解决的方法就是将用户名改成system
- tesseract安装及问题处理
错误1 pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your p ...
- 自动化测试基础篇--Selenium select下拉框
摘自https://www.cnblogs.com/sanzangTst/p/7681523.html 一.什么是下拉框 下拉框是多项选择项,选择其中一种,类似下面(以百度搜索设置为例) 源代码如下所 ...
- SQL Server 锁实验(UPDATE加锁探究)
update语句: 本例中由于看到的是update执行完的锁情况,因此无法看到IU锁,但其实针对要修改的数据页和索引页会先加IU锁,记录和键先加U锁,然后再转化为IX和X锁. 如果想要看到IU锁和U锁 ...
- Django + Uwsgi + Nginx 实现生产环境部署
本节内容 uwsgi 介绍 uwsgi安装使用 nginx安装配置 django with nginx 如何在生产上部署Django? Django的部署可以有很多方式,采用nginx+uwsgi的方 ...