ACM-polya定理

polya定理主要是用于解决等价类计数问题的,所谓等价类计数问题是指题目中会定义一种等价关系,满足这个关系的元素都会被看成同一类,并只需要统计一次,最终需要统计所有的不同方案数。

首先,需要理解等价关系,我们说两个元素是等价的,那么意味着它们满足我们给出的等价条件。等价关系还满足自反性、对称性以及传递性。最终,所有的元素就会被分成若干个等价类,每一个等价类中的元素相互等价,算作一种,不同等价类中的元数则不等价,算作两种。

然后,自然我们就会想去统计等价类的个数。但是,先必须得想办法描述等价关系,一般我们使用置换集合F来描述,如果其中一个置换将一个方案映射到了另一个方案,那么说明二者是等价的。并且置换集合F必须满足,其中任意两个置换的乘积也必须在F中。

接着,我们来看看Burnside定理:如果某一个方案s经过一个置换f后不变,则称s为不动点,将f的所有不动点数目记为c(f),那么等价类数目就等于所有置换的c(f)的平均值。如此一来,我们就可以计算出我们想知道的等价类的数目了。

最后,关键来了,如何计算c(f)呢?以经典的涂色问题为例,如果将置换f分解成m(f)个循环的乘积,并假设涂k种颜色的话,那么c(f)等于k^m(f),详见<<训练指南>>,置换及其应用一章。结合Burnside定理,最终就得到了polya定理:所有置换的k^m(f)的平均值就是等价类的个数。

下面来看看一些典型的等价类置换,背景都是由n个珠子构成的环,并且珠子的颜色总数为t。

1、旋转

如果旋转i颗珠子的间距,那么一共有gcd(i,n)个循环,所以由前面的分析可知其不动点总数为a=t^gcd(0,n) + t^gcd(1,n) + ... + t^gcd(n-1,n)。

2、翻转

分为两种情况。n为奇数时,对称轴有n条,每一条形成(n+!)/2个循环,所以不动点总数为b=n*t^((n+1)/2);当n为偶数时,穿过珠子的对称轴有n/2条,每一条都形成n/2+1个循环,不穿过珠子的对称轴有n/2条,每一条都形成n/2个循环。所以,不动点的总数为b=n/2*(t^(n/2+1)+t^(n/2))。

最后根据polya定理可知,只具有旋转性质的等价类有a/n种,只具有翻转性质的有b/n种,两者都具有的有(a+b)/(2*n)种。由此可知,polya定理的简单应用的关键就是找出置换集合,进而推出不动点的数目。 


下面具体看一道题,HDOJ:3923,时空转移(点击打开链接),题目如下: 

Invoker

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 122768/62768 K (Java/Others)
Total Submission(s): 1164    Accepted Submission(s): 489


Problem Description
On of Vance's favourite hero is Invoker, Kael. As many people knows Kael can control the elements and combine them to invoke a powerful skill. Vance like Kael very much so he changes the map to make Kael more powerful. 

In his new map, Kael can control n kind of elements and he can put m elements equal-spacedly on a magic ring and combine them to invoke a new skill. But if a arrangement can change into another by rotate the magic ring or reverse the ring along the axis, they will invoke the same skill. Now give you n and m how many different skill can Kael invoke? As the number maybe too large, just output the answer mod 1000000007.
 

Input
The first line contains a single positive integer T( T <= 500 ), indicates the number of test cases.
For each test case: give you two positive integers n and m. ( 1 <= n, m <= 10000 )
 

Output
For each test case: output the case number as shown and then output the answer mod 1000000007 in a line. Look sample for more information.
 

Sample Input
  
  
2 3 4 1 2
 

Sample Output
  
  
Case #1: 21 Case #2: 1
Hint
For Case #1: we assume a,b,c are the 3 kinds of elements. Here are the 21 different arrangements to invoke the skills / aaaa / aaab / aaac / aabb / aabc / aacc / abab / / abac / abbb / abbc / abcb / abcc / acac / acbc / / accc / bbbb / bbbc / bbcc / bcbc / bccc / cccc /
 

题意:

用n种颜色涂有m个点的环,求通过旋转和翻转后都不相同的涂色方法。

分析:

正是前面说到的典型等价类置换,用代码实现即可。

源代码:

#include <cstdio>

#define LL __int64
const LL mm=1000000007;
LL mod, pow[10005];
int n, m;

LL gcd(LL a, LL b)
{
    return b==0 ? a : gcd(b,a%b);
}

LL rotat()     //旋转时的不动点
{
    LL ans = 0;
    for (int i=0; i<m; ++i)
        ans = (ans+pow[gcd(i,m)]) % mod;
    return ans;
}

LL overturn()  //翻转时的不动点,分奇偶讨论
{
    LL ans = 0;
    if(m & 1)
        ans = (ans+m*pow[(m+1)/2]) % mod;
    else
        ans = (ans+m/2*(pow[m/2+1]+pow[m/2])) % mod;
    return ans;
}

int main ()
{
    int cas, t=0;
    scanf("%d", &cas);
    while(cas--)
    {
        LL ans = 0;
        scanf("%d%d", &n, &m);
        mod = 2*m*mm;
        pow[0] = 1;
        for(int i=1; i<=m; ++i)
            pow[i] = (pow[i-1]*n) % mod;
        ans += rotat();
        ans  = (ans + overturn()) % mod;
        printf("Case #%d: %I64d\n", ++t, (ans/2/m)%mm);
    }
    return 0;
}

其他类似的题目还有,HDOJ:2084、2647、1812、3411、2865、2481。POJ:1286、2409、2154、2888。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值