# Description

小春现在很清闲, 面对书桌上的 \(N\) 张牌, 他决定给每张染色, 目前小春只有 \(3\) 种颜色: 红色, 蓝色, 绿色. 他询问 Sun 有

多少种染色方案, Sun 很快就给出了答案. 进一步, 小春要求染出 \(Sr\) 张红色, \(Sb\) 张蓝色, \(Sg\) 张绿色. 他又询问有多少种方

案, Sun 想了一下, 又给出了正确答案. 最后小春发明了 \(M\) 种不同的洗牌法, 这里他又问 Sun 有多少种不同的染色方案.

两种染色方法相同当且仅当其中一种可以通过任意的洗牌法 (即可以使用多种洗牌法, 而每种方法可以使用多次) 洗

成另一种. Sun 发现这个问题有点难度, 决定交给你, 答案可能很大, 只要求出答案除以 \(P\) 的余数 (\(P\) 为质数).

并且数据满足 :

输入数据保证任意多次洗牌都可用这 m 种洗牌法中的一种代替,且对每种洗牌法,都存在一种洗牌法使得能回到原状态。

\(Max{(Sr,Sb, Sg)}<=20\)

Solution

群论中的\(burnside\)定理

参考资料: 《组合数学》 或者 网上博客, 感觉《组合数学》讲的很棒QuQ

首先看\(m\)种洗牌, 任意多次都可以用 一种洗牌法来代替, 满足置换群中 合成运算的封闭性

对每种洗牌法, 都存在一种洗牌法使得回到原状态, 满足置换群中 逆元的封闭性

接下来只需要出现单位元就能让洗牌法构成一个置换群

单位元 : 保持所有位置不变的洗牌法(相当于没洗牌)

如果输入的洗牌法没有单位元, 则手动加上一种洗牌法。 就构成了一个置换群。

然后就可以引用 \(burnside\)定理

设 \(f\) 为一种洗牌法,\(c\) 为一种染色法。

我们可以找到有多少个 \(c\) 使得, \(c\) 通过洗牌法\(f\) 洗牌后不变, 记为\(cnt(f)\)。

则最终答案 :

\[ans= \sum cnt(f) \ \div m
\]

证明略(懒得打噜, 网上有)

接下来就要求出 \(cnt(f)\)了:

对于一种洗牌法, 把每个位置都看作一个点, 洗牌的移动看成一条边。 则每个点的出度和入度都是\(1\)

于是构成了若干个不相交的环。要使洗牌后颜色不变, 那么必有同一个环上的颜色相同。

可以通过简单的\(DP\)求出\(cnt(f)\)了!

总复杂度\(O(MN^3)\) ,BZOJ上跑了\(36ms\)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define rd read()
using namespace std; const int N = 62; int n, m, sa, sb, sc, mod;
int nxt[N][N], vis[N], f[22][22];
vector<int> v[N]; int read() {
int X = 0, p = 1; char c = getchar();
for (; c > '9' || c < '0'; c = getchar())
if (c == '-') p = -1;
for (; c >= '0' && c <= '9'; c = getchar())
X = X * 10 + c - '0';
return X * p;
} int fpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1) res = res * a % mod;
return res;
} void init(int x) {
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i) if (!vis[i]) {
vis[i] = 1;
int now = nxt[x][i], tmp = 1;
while (now != i) vis[now] = 1, tmp++, now = nxt[x][now];
v[x].push_back(tmp);
}
} int cal(int x) {
memset(f, 0, sizeof(f));
f[sa][sb] = 1;
int tot = 0;
for (int i = 0, up = v[x].size(); i < up; ++i) {
for (int j = 0; j <= sa; ++j)
for (int k = 0; k <= sb; ++k) {
if (n - tot - j - k < v[x][i]) f[j][k] = 0;
if (j + v[x][i] <= sa) (f[j][k] += f[j + v[x][i]][k]) %= mod;
if (k + v[x][i] <= sb) (f[j][k] += f[j][k + v[x][i]]) %= mod;
}
tot += v[x][i];
}
return f[0][0];
} int main()
{
sa = rd; sb = rd; sc = rd; m = rd; mod = rd;
n = sa + sb + sc;
bool flag = false;
for (int i = 1; i <= m; ++i) {
bool is = true;
for (int j = 1; j <= n; ++j) {
nxt[i][j] = rd;
if (nxt[i][j] != j) is = false;
}
if (is) flag = true;
}
if (!flag) {
m++;
for (int i = 1; i <= n; ++i)
nxt[m][i] = i;
}
for (int i = 1; i <= m; ++i)
init(i);
int ans = 0;
for (int i = 1; i <= m; ++i)
ans = (ans + cal(i)) % mod;
ans = ans * fpow(m, mod - 2);
ans = (ans + mod) % mod;
printf("%d\n", ans);
}

1004: [HNOI2008]Cards - burnside + DP的更多相关文章

  1. bzoj 1004 1004: [HNOI2008]Cards burnside定理

    1004: [HNOI2008]Cards Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1668  Solved: 978[Submit][Stat ...

  2. BZOJ 1004 HNOI2008 Cards Burnside引理

    标题效果:特定n张卡m换人,编号寻求等价类 数据保证这m换人加上置换群置换后本身构成 BZOJ坑爹0.0 条件不那么重要出来尼玛怎么做 Burnside引理--昨晚为了做这题硬啃了一晚上白书0.0 都 ...

  3. 1004: [HNOI2008]Cards burnside定理

    https://www.lydsy.com/JudgeOnline/problem.php?id=1004 输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种洗牌法,都存在一种洗牌法使 ...

  4. BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )

    题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...

  5. 【BZOJ 1004】 1004: [HNOI2008]Cards (置换、burnside引理)

    1004: [HNOI2008]Cards Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很 ...

  6. [HNOI2008]Cards(dp,Burnside引理)

    Burnside引理: 参考自 某大佬对Burnside引理和Polya定理的讲解 相关概念 群:在数学中,群表示一个拥有满足封闭性.满足结合律.有单位元.有逆元的二元运算的代数结构. 置换群:由有限 ...

  7. 【BZOJ1004】[HNOI2008]Cards Burnside引理

    [BZOJ1004][HNOI2008]Cards 题意:把$n$张牌染成$a,b,c$,3种颜色.其中颜色为$a,b,c$的牌的数量分别为$sa,sb,sc$.并且给出$m$个置换,保证这$m$个置 ...

  8. bzoj1004 [HNOI2008]Cards Burnside 引理+背包

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1004 题解 直接 Burnside 引理就可以了. 要计算不动点的个数,那么对于一个长度为 \ ...

  9. [BZOJ 1004] [HNOI2008] Cards 【Burnside引理 + DP】

    题目链接:BZOJ - 1004 题目分析 首先,几个定义和定理引理: 群:G是一个集合,*是定义在这个集合上的一个运算. 如果满足以下性质,那么(G, *)是一个群. 1)封闭性,对于任意 a, b ...

随机推荐

  1. jQuery获取各种位置方法

    一.获取窗口的宽高 1.获取流览器显示区域的高度 : $(window).height(); 2.获取流览器显示区域的宽度 : $(window).width(); 3.获取文档流的高度 : $(do ...

  2. Laragon+PHP7中开启xdebug

    状态 :laragon+php7.2,按管方做法要求用的是xdebug2.7.结果2.7版本放进去一打断点就挂了,于是换成2.6的版本, php.ini中配置如下: [Xdebug] zend_ext ...

  3. 关于c# Debug和Release的区别 (转)

    关于Debug和Release的区别之讨论本文主要包含如下内容: 1. Debug 和 Release 编译方式的本质区别2. 哪些情况下 Release 版会出错2. 怎样“调试” Release ...

  4. HTML5 前端将 dom 元素转化为 Word,EXCEL 或者图片 并实现下载

    < 一 >  word  1,依赖于 jquery.html.word.js 插件 => https://blog-static.cnblogs.com/files/lovling/ ...

  5. Swoft 容器使用

    可以借助Swoft下的Bean类操作容器 示例: 将类绑定至容器 use Swoft\Bean\Annotation\Bean; /** * @Bean("imageLogic") ...

  6. pytorch安装 caffe2 安装:git 慢 caffe2 cannot find -lopencv_dep_cudart ,undefined reference to 'pthread_create'

    最开始的问题: caffe2目前已经不维护了.怎么编译都报错,并且有third_party的代码链接已经飞了.下载不全代码了.建议 不要再折腾了,直接安装Pytorch. 首先,基本环境是ubuntu ...

  7. 不学无术的下场——OO第一单元总结

    第一单元OO作业总结 第一次作业 ​ 第一次作业的要求是对仅有常数和幂函数的式子进行求导. ​ 由于是第一次接触JAVA,对很多东西都还不熟悉,尤其是正则表达式做得不好.当时我的思路如下: 建立Pol ...

  8. Python 中文数字转阿拉伯数字

    #只能转数字,传参中包含非数字会错. def t(str): zhong={'零':0,'一':1,'二':2,'三':3,'四':4,'五':5,'六':6,'七':7,'八':8,'九':9}; ...

  9. (ZT)算法杂货铺——分类算法之决策树(Decision tree)

    https://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html 3.1.摘要 在前面两篇文章中,分别介绍和讨论了朴素贝叶斯分 ...

  10. MPC学习笔记1:基于状态空间模型的预测控制(2)

    基于估计的无约束预测控制 1.引言 基本上这两个部分都是在线性理论的框架下,利用状态空间法来建模.求解控制律.状态空间模型在理论分析上具有很强的优越性,但实际应用中能直接准确且经济地获取系统状态并不容 ...