ploya定理 学习总结#by nobody

本小结会不断更新,转载请注明出处:http://blog.csdn.net/xdu_truth/article/details/8033524


(1)循环:
         在一个置换下 如果x1->x2,x2->x3,...,xn->x1;
         x1,x2,x3,...,xn就形成了一个循环。   
(2)ploya定理:
        定义ck为在置换ak下的循环总数
        设G = {a1,a2,a3,...,a|G|}是N ={1,2,3,...,N}上的置换群,现用m种颜色对着N个点染色,则不同的染色方案数为:
     S = (m^c1 + m^c2 + ... + m^c|G|)/|G|
(3)常见置换的循环数:
        旋转:  n个点顺时针(或逆时针)旋转i个位置的置换,循环数为gcd(n,i)
        翻转:
  n为偶数时:  对称轴不过顶点:循环数为n/2;
                  对称轴过顶点:循环数为n/2+1;
  n为奇数时:循环数为(n+1)/2;


pku2409 Let it Bead (公式题)


code:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int gcd(int a,int b)
{
    return b==0 ? a:gcd(b,a%b);
}


int _pow(int p,int n)
{
    int ret = 1;
    while(n)
    {
        if(n&1)ret *= p;
        p *= p;
        n /= 2;
    }
    return ret;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&m,&n),n|m)
    {
        int ans = 0;
        for(int i=1;i<=n;i++)
            ans += _pow(m,gcd(n,i));
        if(n&1)
            ans += n*_pow(m,(n+1)/2);
        else ans += (n/2)*_pow(m,n/2)+(n/2)*_pow(m,n/2+1);
        ans /= (2*n);
        printf("%d\n",ans);
    }
    return 0;
}





另外POJ上还有个公式题http://poj.org/problem?id=1286
这个题注意项链珠数为0的情形,之前一直RE,把我恶心到了。


----------------------------------------------------我是华丽的分割线---------------------------------------------------



pku2154 Color
题意:给出两个整数n和p,代表n个珠子,n种颜色,要求不同的项链数(旋转重合算同一种,翻转重合不算同一种),并对结果mod(p)处理。
不错的一个数学题,
根据ploya定理,结果为:(1/n * ∑n^gcd(n,i)) % p (i=1,..,n)
但是n<=1000000000,显然这个公式需要化简一下。
gcd(n,i)的所有取值是n的所有约数,所以对于某个约数x,我们考虑n^x系数:
由于gcd(n,i) = x ,
那么gcd(n/x,i/x) = 1,
所以系数即为所有满足上式的i的个数,即欧拉函数 euler(n/x);
这样公式就化简为了: (1/n * ∑Euler(n/x)(n^x)) % p   (x为n的所有约数)


code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n,mod;
int powmod(int p,int m)
{
    int ret = 1;
    while(m)
    {
        if(m&1)ret=(ret * p)%mod;
        p = (p*p)%mod;
        m >>= 1;
    }
    return ret;
}
int euler(int x)
{
    int res = x;
    for(int i=2;i<(int)sqrt(x*1.0)+1;i++)
    {
        if(x%i == 0)
        {
            res = res/i*(i-1);
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)res = res/x*(x-1);
    return res%mod;
}
int main()
{
    //freopen("input.txt","r",stdin);
    int cases;
    scanf("%d",&cases);
    while(cases-- && scanf("%d%d",&n,&mod))
    {
        int ans = 0;
        for(int x=1;x*x<=n;x++)
        {
            if(n%x==0)
            {
                ans = (ans+euler(n/x)*powmod(n%mod,x-1))%mod;
                if(n/x != x)ans = (ans+euler(x)*powmod(n%mod,n/x-1))%mod;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(c)