题目链接:BZOJ - 1004

题目分析

首先,几个定义和定理引理:

群:G是一个集合,*是定义在这个集合上的一个运算。

如果满足以下性质,那么(G, *)是一个群。

1)封闭性,对于任意 a, b 属于 G, a * b 属于 G

2)结合律, a * b * c = a * (b * c)

3)单位元,在 G 中存在一个单位元 e ,使得对于 G 中任意的 a , a * e = e * a = a

4)逆元, 对于 G 中任意的 a ,在 G 中存在 b , 使得 a * b = e , 其中 b 叫做 a 的逆元

比如在模一个数意义下的整数加法就是一个群。

满足交换律的群是交换群,又叫阿贝尔群。

置换:可以用 (a1 -> b1, a2 -> b2, ... , an -> bn) 表示一个置换,其中 a1, ... , an 和 b1, ..., bn 都是1 到 n 的一个排列;

如果一些置换和它们的叠加运算构成一个群,就把它们叫做一个置换群。

在置换群中的 Burnside 引理:如果按照一定要求,要对1到n 的位置染色,那么本质不同的染色方案数为置换群中每个置换的不动染色方案数的平均数。

来解释以下,本质不同的染色方案是指,两个染色方案不能通过置换群中的任意置换变换使其相同,那么它们就是本质不同的。

某个置换的不动染色方案数是指,用这个置换变换之后没有发生变化的染色方案。

那么我们就是要求出每个置换的不动染色方案数。

Polya定理告诉我们,如果是用k种颜色染色,那么对于置换 P 来说,它的不动染色方案数为 k^(L(P)), 其中L(P)为置换P的循环节数。

这个很好理解,因为每个循环节如果要使置换之后不改变的话,应该使这个循环节中都染同一种颜色。

但是,这道题的染色要求是给定了3种颜色的数量,就不能用 k^(L(P)) 来求了。

我们使用一种3维DP,还是先搜索一遍求出这个置换的所有循环节的大小。然后把每个循环节看作一个物品,染一种颜色。

用 f[i][j][k] 表示染了前 i 件物品,第1种颜色用了 j 个, 第2种颜色用了 k 次的染色方案数。

这道题还需要注意的一点是,需要加上一个不做任何改变的置换作为单位元才能成为一个置换群。

这个单位元的不动染色方案数就是所有的染色方案数,直接用多重集排列就好了, n! / (a! b! c!)。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm> using namespace std; const int MaxN = 60; int Na, Nb, Nc, n, m, Mod, Ans, Top;
int A[MaxN], V[MaxN], Sum[MaxN], f[MaxN][MaxN][MaxN]; bool Used[MaxN]; inline int Pow(int a, int b)
{
int ret = 1, f = a;
while (b)
{
if (b & 1)
{
ret *= f;
ret %= Mod;
}
b >>= 1;
f *= f;
f %= Mod;
}
return ret;
} inline int NY(int x) {return Pow(x, Mod - 2);} void DFS(int x, int Num)
{
if (Used[x])
{
V[++Top] = Num;
return;
}
Used[x] = true;
DFS(A[x], Num + 1);
} inline int Fac(int x)
{
int ret = 1;
for (int i = 1; i <= x; ++i)
{
ret *= i;
ret %= Mod;
}
return ret;
} int main()
{
scanf("%d%d%d%d%d", &Na, &Nb, &Nc, &m, &Mod);
n = Na + Nb + Nc;
Ans = Fac(n) * NY(Fac(Na)) % Mod * NY(Fac(Nb)) % Mod * NY(Fac(Nc)) % Mod;
for (int i = 1; i <= m; ++i)
{
for (int j = 1; j <= n; ++j)
{
scanf("%d", &A[j]);
Used[j] = false;
}
Top = 0;
for (int j = 1; j <= n; ++j)
if (!Used[j]) DFS(j, 0);
Sum[0] = 0;
for (int j = 1; j <= Top; ++j)
Sum[j] = Sum[j - 1] + V[j];
f[0][0][0] = 1;
for (int j = 1; j <= Top; ++j)
{
for (int p = 0; p <= Na; ++p)
{
for (int q = 0; q <= Nb; ++q)
{
f[j][p][q] = 0;
if (p >= V[j])
{
f[j][p][q] += f[j - 1][p - V[j]][q];
f[j][p][q] %= Mod;
}
if (q >= V[j])
{
f[j][p][q] += f[j - 1][p][q - V[j]];
f[j][p][q] %= Mod;
}
if ((Sum[j] - p - q) >= V[j])
{
f[j][p][q] += f[j - 1][p][q];
f[j][p][q] %= Mod;
}
}
}
}
Ans += f[Top][Na][Nb];
Ans %= Mod;
}
Ans *= NY(m + 1);
Ans %= Mod;
printf("%d\n", Ans);
return 0;
}

  

[BZOJ 1004] [HNOI2008] Cards 【Burnside引理 + DP】的更多相关文章

  1. BZOJ 1004 HNOI2008 Cards Burnside引理

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

  2. bzoj1004: [HNOI2008]Cards(burnside引理+DP)

    题目大意:3种颜色,每种染si个,有m个置换,求所有本质不同的染色方案数. 置换群的burnside引理,还有个Pólya过几天再看看... burnside引理:有m个置换k种颜色,所有本质不同的染 ...

  3. BZOJ 1004: [HNOI2008]Cards [Polya 生成函数DP]

    传送门 题意:三种颜色,规定使用每种颜色次数$r,g,b$,给出一个置换群,求多少种不等价着色 $m \le 60,\ r,g,b \le 20$ 咦,规定次数? <组合数学>上不是有生成 ...

  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 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1668  Solved: 978[Submit][Stat ...

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

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

  7. BZOJ 1004 Cards(Burnside引理+DP)

    因为有着色数的限制,故使用Burnside引理. 添加一个元置换(1,2,,,n)形成m+1种置换,对于每个置换求出循环节的个数, 每个循环节的长度. 则ans=sigma(f(i))/(m+1) % ...

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

    题目描述 用三种颜色染一个长度为 $n=Sr+Sb+Sg$ 序列,要求三种颜色分别有 $Sr,Sb,Sg$ 个.给出 $m$ 个置换,保证这 $m$ 个置换和置换 ${1,2,3,...,n\choo ...

  9. BZOJ1004: [HNOI2008]Cards(Burnside引理 背包dp)

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4255  Solved: 2582[Submit][Status][Discuss] Descript ...

随机推荐

  1. 【OpenCV十六新手教程】OpenCV角检测Harris角点检测

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/29356187 作者:毛星云(浅墨) ...

  2. Cocos2d-x中获取设备语言的方法

    1.cocos2dx获取设备语言的方法:CCApplication::sharedApplication()->getCurrentLanguage() 2.cocos2dx 2.1.4支持识别 ...

  3. oracle多表查询

    多表查询首先要避免笛卡尔集,要避免笛卡尔集,那么查询条件不得少于表的个数-1. 1.显示雇员名,雇员工资以及雇员所在的部门: 2.显示部门号为10的部门名.员工名和工资: 3.显示各个雇员的姓名,工资 ...

  4. Google Map API v2 步步为营(一) ----- 初见地图

    官方文档:https://developers.google.com/maps/documentation/android/start?hl=zh-CN 先谷歌后百度.使用google的api基本上按 ...

  5. Modem常用概念

    真实设备的标识,即DEVICE_ID.比如,Android设备是手机,这个DEVICE_ID可以同通过TelephonyManager.getDeviceId()获取,它根据不同的手机设备返回IMEI ...

  6. C# 与 C++ 交互

    参考: http://www.cnblogs.com/liping13599168/archive/2011/03/31/2000320.html Platform Invoke Tutorial:h ...

  7. SQL Server 表字段值转列名 示例

    前几天,同事问我怎样把字段值转换成字段列,就写了一个最简单的Demo分享一下. 代码如下: -- 创建测试表以及添加测试数据create table #temp(a money,b varchar(1 ...

  8. Linux上安装KDE, Gnome和VNC

    安装所需环境:需要至少256m的可用内存(128也可以不过有点卡)CentOS或类似OS(Debian的话改成apt-get应该也可以) 1,安装KDE 1 yum install kdepim 或安 ...

  9. FXBlurView用法

    FXBlurView是UIView的子类,它实现毛玻璃效果的原理其实就是覆盖上一层FXBlurView的实例对象. - (void)viewDidLoad { [super viewDidLoad]; ...

  10. JS常用的7中跨域方式总结

    javascript跨域有两种情况:  1.基于同一父域的子域之间,如:a.c.com和b.c.com  2.基于不同的父域之间,如:www.a.com和www.b.com  3.端口的不同,如:ww ...