机器人的项链 HDU

来源:互联网 发布:淘宝手机详情文字大小 编辑:程序博客网 时间:2024/04/29 05:59

机器人的项链 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 1000001int euler[Max];void Init(){      euler[1]=1;     for(int i=2;i<Max;i++)       euler[i]=i;     for(int i=2;i<Max;i++)        if(euler[i]==i)           for(int j=i;j<Max;j+=i)              euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出 }/*对于这个题,需要对欧拉函数进行一个简单 的“优化”。否者会超时。即先筛素数再用模板。euler (x): 1~x中互质的数的个数,***   euler(n/i): 1~n中有多少个数的最大公约数是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;j<cnt && i*prime[j]<=N;j++){isprime[i*prime[j]]=true;}}cnt--;isprime[1]=true;}ll euler(ll n){ll i;ll tempn=n;ll ans=n;for(i=0;i<=cnt && prime[i]*prime[i]<=n;i++){if(n%prime[i]==0){ans=ans/prime[i]*(prime[i]-1);while(tempn%prime[i]==0)tempn/=prime[i];}}if(tempn>1)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<stdio.h>#include<iostream>#include<string.h>#include<string>#include<stdlib.h>#include<math.h>#include<vector>#include<list>#include<map>#include<stack>#include<queue>#include<algorithm>#include<numeric>#include<functional>#define maxn 80010using 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&&i<len;i++)     {         if(a%prime[i]==0)         {             res=res/prime[i]*(prime[i]-1);             while(a%prime[i]==0) a/=prime[i];         }     }     if(a>1) 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;}




 
原创粉丝点击