机器人的项链 HDU - 2239 欧拉函数 Polya定理

机器人的项链 HDU - 2239



刚开始做欧拉函数的题目,先说一下欧拉函数吧。

euler(x)就是计算1~n中有多少个与n互质的个数;

公式:euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn);

具体实现两种:

//1.

int euler(int n)
{ //返回euler(n) 
     int res=n,a=n;
     for(int i=2;i*i<=a;i++)
     {
         if(a%i==0)
         {
             res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出 
             while(a%i==0) a/=i;
         }
     }
     if(a>1) res=res/a*(a-1);
     return res;
}


//2,打表

//筛选法打欧拉函数表 
#define Max 1000001
int euler[Max];
void Init()
{ 
     euler[1]=1;
     for(int i=2;i

即:

int prime[maxn];
bool isprime[maxn];
int cnt;
void Init()
{
    cnt=0;
    memset(isprime,0,sizeof isprime);
	ll i,j;
	for(i=2;i<=N;i++)
	{
		if(!isprime[i])
			prime[cnt++]=i;
		for(j=0;j1)
		ans=ans/tempn*(tempn-1);
	return ans;
}



再说一下Polya定理:

    



是n个对象的一个置换群, 用m种颜色染图这n个对象,则不同的染色方案数为:


其中
,为的循环节数

简单来讲就是用m中颜色去染n个对象,这n个对象是环状的,求方案数。
置换:设X为一个有限集,π是X到X的一个--变换,那么称π是X上的一个置换。
比如:
{ 1 2 3 4 5 }的置换群{ (1 2 3 4 5 ) ( 2 3 4 5 1) (3 4 5 1 2) (4 5 1 2 3) (5 1 2 3 4) } 
循环节:
 1 2 3 4 5 
 3 4 1 2 5   循环节就是比较上下两个数列:如果出现上面的与下面的集合能够出现全等。
                 比如:上面的1->3,3->1,这就是一个循环节,同样{ 2->4,4->4},{ 5->5 },一共三个循环节。
循环节的求法:
把所有置换写出来,就能知道它们的循环节数了;
对于旋转,有c(ai) = gcd(n,i),i为转动幅度,1~n,gcd是求最大公约数。
对于 这个题:ans=sum(m^gcd(n,i))/n;
又因为n很大,所以要用欧拉函数处理,即用欧拉函数枚举n的约数 ,找到最大公约数为 i 的个数,ans=Sum(euler(n/i)*m^i)/n;
除n本来要用逆元,但是有些数的逆元不存在,所以不能用,
正确做法是枚举每个数找到ans最小值。
代码:


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 80010
using namespace std;

const  int MOD=9937;
typedef long long ll;

bool vis[maxn];
int prime[maxn];
int len;
void Init()
{
    len=0;
    memset(vis,0,sizeof vis);
    for(int i=2;i<=maxn;i++)
    {
        if(!vis[i])
        {
           prime[len++]=i;
           for(int j=i*2;j<=maxn;j+=i)
                vis[j]=1;
        }
    }
}
int euler(int n)
{
     int res=n,a=n;
     for(int i=0;(ll)prime[i]*prime[i]<=a&&i1) res=res/a*(a-1);
     return res%MOD;
}
int Pow(int a,int b)
{
    a%=MOD;
    int res=1;
    while(b)
    {
        if(b&1)
            res=res*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return res;
}
int main()
{
    int  n,m;
    Init();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        ll ans=0;
        for(int i=1;i<=sqrt(n)+1;i++)
        {
            if(n%i==0)
            {
                ans=(ans+euler(n/i)*Pow(m,i)%MOD)%MOD;
                if(i!=n/i)
                    ans=(ans+euler(i)*Pow(m,n/i)%MOD)%MOD;// 注意n/i 的计算
            }
        }
        int tot = ans;
        for (ans = 0; ans < MOD; ans++)
            if ((ll)ans*n % MOD == tot % MOD)
                break;
        printf ("%d\n", ans);
    }
    return 0;
}


























你可能感兴趣的:(欧拉函数)