Polya定理

polya定理主要是用于解决等价类计数问题的,所谓等价类计数问题是指题目中会定义一种等价关系,满足这个关系的元素都会被看成同一类,并只需要统计一次,最终需要统计所有的不同方案数。polya定理主要就是解决一类着色问题,对于任意的带变换的着色计数问题,我们都可以把变换用置换群表示出来,或者说是同构计数问题。设染色方案数是n,置换群个数是p,置换群长度是s,那么利用Burnside引理,通过考察每个染色方案和每个置换群,可以在 O(nsp)时间复杂度计算出答案。

考虑旋转和翻转

1.旋转置换.

我们假设依次顺时针旋转 1n,则循环个数为 gcd(i,n)

2.翻转置换

n 为偶数时,分两种情况:

一种是中心轴在两个对称对象上,则循环个数为 n/2+1,这样的置换有 n/2 个。

另一种是对称轴两边分别有 n/2 个对象,则循环个数为 n/2,这样的置换也有 n/2 个。

n 为奇数时,对称轴就只能在一个对象上,则循环个数为 n/2+1

Polya定理:

定义置换群G,其中的每一个置换f若使得f(x)等于y,则xy本质相同。

 

使用c中颜色对n个点染色,其本质不同的方案数为:

 

1|G|(cf1+cf2++cf|G|)

其中c^fn指置换群G中第n个置换的循环节个数(轨道数)。

对于每一个置换群考虑其|C(f)|的个数,这可以通过递推、DP、或者是矩阵快速幂来解决。


HOJ 2084 The Colored Cubes
HOJ 2647 Megaminx
POJ 1286 Necklace of Beads
POJ 2409 Let it Bead

TOJ 2795 The Queen’s New Necklaces

POJ 2154 Color

POJ 2888 Magic Bracelet

模板:

#define N 32000
int G;
long long mod;
bool notprime[N];
int prime[N],pp;
int fac[50][3],fp;   //0:质数p 1:次数k 2:p^k

void init_prime()       //筛质数
{
    for( int i=2;i<N;i++ ){
        if( !notprime[i] ) prime[ pp++ ]=i;
        for( int j=0;j<pp&&i*prime[ j ]<N;j++ ){
            notprime[ i*prime[ j ] ]=true;
            if( i%prime[ j ]==0 ) break;
        }
    }
}

void fact(int a)           //分解质因数
{
    int n=a;
    fp=0;
    for(int i=0;i<pp&&prime[i]*prime[i]<=a&&n>1;i++)
        if(n%prime[i]==0){
            for(fac[fp][0]=prime[i],fac[fp][1]=0,fac[fp][2]=1;n%prime[i]==0;n/=prime[i],fac[fp][1]++,fac[fp][2]*=prime[i]);
            fp++;
        }
    if(n>1) fac[fp][0]=n,fac[fp][1]=1,fac[fp++][2]=n;
}

long long getv( int n )    //计算对应的C(f)
{
    
}

void DFS(long long &res,int g,int phi,int d) //枚举因子
{
    if(d==fp){
        res=(res+1ll*phi*getv(g))%mod;
        return;
    }
    for( int i=0,p=fac[d][2];i<=fac[d][1];i++,p/=fac[d][0] )
        DFS( res,fac[d][2]/p*g,phi*(p-p/fac[d][0]),d+1 );
}

void ex_gcd( long long &x,long long &y,long long a,long long b )
{
    if( !b ) x=1,y=0;
    else{
        ex_gcd( x,y,b,a%b );
        long long t=y;
        y=x-a/b*y,x=t;
    }
}

long long cal()
{
    fact( G );
    long long ret=0,x,y;
    DFS( ret,1,1,0 );    
    ex_gcd( x,y,G,mod );
    x%=mod;
    ret=(ret*x%mod+mod)%mod;
    return ret;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值