参考了http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove 的模板

对于每一种染色,都有一个等价群,例如旋转,翻转等。我们将每一种变换转换成一个置换群,通过置换群得到的都是等价的染色方案

最终我们要求的是非等价的染色方案数。

在Burnside定理中给出,在每一种置换群也就是等价群中的数量和除以置换群的数量,即非等价的着色数等于在置换群中的置换作用下保持不变的着色平均数。

我们以POJ 2409 Let it Bead为例http://poj.org/problem?id=2409

N个物品的环,M种颜色。非常基础的问题

那么总共有多少个置换群呢,显然旋转是等价的,那么包括旋转0度,总共便是N个旋转。

对于每一个旋转的等价数量怎么算呢。我们发现每一个旋转置换中有若干个循环节,例如1,3,5是一个循环节,那么旋转一次,1号位到了3号位,3号位到了5号位,显然一个循环节内的颜色一定是一样的。有M种颜色选择,问题转换成有多少个循环节。对于旋转显然有GCD(i,n)。那只要枚举i便可以,这就是Polya定理。

而在翻转当中,如果N为奇数,明显有一个物品是不动的,其它的两两对称,颜色也是一样的。n/2+1个循环节,

如果 N为偶数,分为两种情况,一种是对称轴不过物品,那么所有物品两两对应,n/2个循环节,另外一种是对称轴经过两个物品,(n-2)/2+1+1个循环节。对于每一个循环节有M种颜色可以选择。

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 100005
#define inf 1<<29
#define MOD 2007
#define LL long long
using namespace std;
LL gcd(LL a,LL b){
return b==?a:gcd(b,a%b);
}
LL Pow(LL a,int b){
LL ret=;
while(b){
if(b&)
ret=ret*a;
a=a*a;
b>>=;
}
return ret;
}
LL Polya(int n,int m){
LL sum=;
//枚举n种旋转
for(int i=;i<=n;i++)
//每个循环节是m种颜色可选
//总共有gcd(n,i)个循环节
sum+=Pow(m,gcd(n,i));
if(n&)
//如果为奇数,所有位置上的循环节数量都为n/2+1
sum+=n*Pow(m,n/+);
else
//否则要分奇偶,各一半
sum+=n/*Pow(m,n/)+n/*Pow(m,n/+);
return sum//n;
}
int n,m;
int main(){
while(scanf("%d%d",&m,&n)!=EOF&&n+m){
printf("%lld\n",Polya(n,m));
}
return ;
}

对于N如果非常大的话,枚举旋转就非常耗时。接下来可以有个优化

我们枚举循环节长度L,那么循环节个数便是N/L,必然L必须是N的约数才行。

那么d=N/L=gcd(i,N),对于每一个L,我们需要求出有多少个i满足左边的式子。

令i=d*t,gcd(d*t,L*d)=d,要左边的式子成立,明显gcd(t,L)==1,否则最大公约数不为d。

那么对于任意的t满足与L互质即可,便是L的欧拉函数值

这样就可以在sqrt(n)的复杂度内枚举L, ∑(phi(L) * M^(N/L) ) % p  (L即枚举值) 。

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 100005
#define inf 1<<29
#define MOD 2007
#define LL long long
using namespace std;
LL gcd(LL a,LL b){
return b==?a:gcd(b,a%b);
}
LL Eular(LL n){
LL ret=;
for(int i=;i*i<=n;i++){
if(n%i==){
n/=i;
ret*=i-;
while(n%i==){
n/=i;
ret*=i;
}
}
}
if(n>) ret*=n-;
return ret;
}
LL Pow(LL a,LL b){
LL ret=;
while(b){
if(b&)
ret=ret*a;
a=a*a;
b>>=;
}
return ret;
}
LL Polya(int n,int m){
LL sum=;
int i;
for(i=;i*i<n;i++)
if(n%i==){
sum+=Eular(i)*Pow(m,n/i);
sum+=Eular(n/i)*Pow(m,i);
}
if(i*i==n) sum+=Eular(i)*Pow(m,i);
if(n&)
sum+=n*Pow(m,n/+);
else
sum+=n/*Pow(m,n/)+n/*Pow(m,n/+);
return sum//n;
}
int n,m;
int main(){
while(scanf("%d%d",&m,&n)!=EOF&&n+m)
printf("%lld\n",Polya(n,m));
return ;
}

Source Code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define MOD 1000000007
#define LL long long
using namespace std;
int prime[]={,,,,,,,,,,,,,,
,,,,,,,,,,,},cnt=;
LL n,m;
LL eular(LL n){
LL sum = ;
for(int i = ; i <= sqrt(1.0 + n); ++i)
if(n % i==){
sum *= (i-);
n /= i;
while(n % i == ){
sum *= i;
n /= i;
}
}
if(n > )
sum *= (n-);
return sum % MOD;
}
LL Pow(LL a,LL b){
LL ret=;
while(b){
if(b&)
ret=(ret*a)%MOD;
a=(a*a)%MOD;
b>>=;
}
return ret;
}
LL Polya(){
LL sum=,i;
for(i=;i*i<n;i++){
if(n%i==){
sum=(sum+eular(i)*Pow(m,n/i))%MOD;
sum=(sum+eular(n/i)*Pow(m,i))%MOD;
}
}
if(i*i==n)
sum=(sum+eular(i)*Pow(m,i))%MOD;
if(n&)
sum=(sum+n*Pow(m,n/+))%MOD;
else
sum=(sum+n/*(Pow(m,n/)+Pow(m,n/+)))%MOD;
return (sum*Pow(*n,MOD-))%MOD;
}
int main(){
LL t,cas=;
scanf("%I64d",&t);
while(t--){
scanf("%I64d%I64d",&m,&n);
printf("Case #%I64d: %I64d\n",++cas,Polya());
}
return ;
}

HDU 3923 Invoker 【裸Polya 定理】的更多相关文章

  1. HDU 3923 Invoker(polya定理+逆元)

    Invoker Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 122768/62768 K (Java/Others)Total Su ...

  2. poj 1286 Necklace of Beads poj 2409 Let it Bead HDU 3923 Invoker <组合数学>

    链接:http://poj.org/problem?id=1286 http://poj.org/problem?id=2409 #include <cstdio> #include &l ...

  3. HDU 3923 Invoker | 暑训Day1 C题填坑

    暑训第一天,专题为组合数学与概率期望. 最近一个月都没有学习新的知识,上午听聚聚讲课头脑都是一片空白.加上长期没刷题,下午做练习题毫无感觉.到晚上总算理清了蓝书上的一些概念,跟着榜单做题.最后唯独剩下 ...

  4. HDU 3923 Invoker(polya定理+乘法逆元(扩展欧几里德+费马小定理))

    Invoker Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 122768/62768K (Java/Other) Total Subm ...

  5. [ACM] hdu 3923 Invoker (Poyla计数,高速幂运算,扩展欧几里得或费马小定理)

    Invoker Problem Description On of Vance's favourite hero is Invoker, Kael. As many people knows Kael ...

  6. hdu 3923 Invoker

    完全是套用polya模版…… ;}

  7. HDU 4633 Who's Aunt Zhang (Polya定理+快速幂)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4633 典型的Polya定理: 思路:根据Burnside引理,等价类个数等于所有的置换群中的不动点的个 ...

  8. hdu 1817 Necklace of Beads(Polya定理)

    Necklace of Beads Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  9. hdu 3547 (polya定理 + 小高精)

    DIY CubeTime Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Sub ...

随机推荐

  1. 设计模式的PHP实现示例(转)

    symfony2 很多设计模式思想,下面的资料会有点帮助:http://www.open-open.com/lib/view/open1414996676559.html 阅读目录 Creationa ...

  2. 神奇的魔法数字0x61c88647

    来源JDK源码,产生的数字分布很均匀 用法代码如下. # -*- coding: utf-8 -*- HASH_INCREMENT = 0x61c88647 def magic_hash(n): fo ...

  3. 驯服你的Windows Server 2003

    虽然通过一些技巧可以让Windows Server 2003更符合我们的使用习惯,但对我等菜鸟来说,操作还是有相当的难度,有没有更简单.更省事的驯服它的办法呢?有,那就是使用Windows Serve ...

  4. C++中的内存对齐

    在我们的程序中,数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度. 我们还是先来看一段简单的程序: 程序一 1 #include  ...

  5. WINDOWS硬件通知应用程序的常方法

    摘要:在目前流行的Windows操作系统中,设备驱动程序是操纵硬件的最底层软件接口.为了共享在设备驱动程序设计过程中的经验,给出设备驱动程序通知应用程序的5种方法,详细说明每种方法的原理和实现过程,并 ...

  6. 一个异或加密方案--C语言实现

    核心代码: char encrypt( char f , char c) { return f^c; } int OutEncrypt( char *FilePath, char *SecretWor ...

  7. Linux系统服务 1 ---- rSyslog日志服务

    1 日志 1 日志是系统用来记录系统运行时候的一些相关的信息的纯文本文件 2 日志的目的是保存相关程序的运行状态,错误信息等.为了对系统进行分析,保存历史记录以及在出现错误的时候发现分析错误使用 3 ...

  8. linux下笔记本有线网卡"未受管理"

    前段时间因为在弄一个笔记双网卡共享上网的事情把笔记本的有线网卡弄环了,连接的时候一直出现如下情况: 1)有线网卡:未受管理 2)无线网卡:每次登录的时候必须把原来登录过的信息删除掉,然后重新输入密码, ...

  9. CSS中的repeat

    Repeat-x是横向铺满,就是图片会横向重复,直到铺满. Repeat-y是纵向铺满,就是让图片纵向重复,直到铺满. 如果不想让重复,就直接为:no-repeat.

  10. 【前端】使用weinre对手机、微信浏览器页面调试

    官方网站:http://people.apache.org/~pmuellr/weinre-docs/latest/ windows下安装以及使用: 1.安装nodejs 下载nodejs引擎,32b ...