首页 > 代码库 > POJ 3358 (欧拉定理)

POJ 3358 (欧拉定理)

题目:求 q/p 二进制小数的循环节,起点和长度。


若满足 2^phi[ n ] = 1 (mod n )   则 数 t = phi [ n ] 一定有一个使 2^k=1 (mod n )成立的 因子 k 


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#define bug(a) cout<<a<<"--->\n";
#define N 100000
using namespace std;

typedef unsigned long long  LL;

LL euler_phi(LL n)
{
    LL m=(LL)sqrt(n+0.5);
    LL ans=n;
    for(LL i=2;i<=m;i++)
    {
        if(n%i==0){
        ans=ans/i*(i-1);
        while(n%i==0) n/=i;
        }
    }
    if(n>1) ans=ans/n*(n-1);
    return ans;
}

LL gcd(LL a,LL b)
{
    LL r;
    if(b>a) swap(a,b);
    while(b)
    {
        r=a%b;
        a=b;
        b=r;
    }

    return a;
}


void factor(LL n,LL *fac,int &cnt)    //求因数,保存于 fac[1001]
{
    cnt=0;
    LL m=(LL)sqrt(n+0.5);
    for(LL i=1;i<=m;i++)
    {
        if(n%i==0)
        {
            fac[cnt++]=i;
            fac[cnt++]=n/i;
        }
    }
    sort(fac,fac+cnt);
}

LL qpow(LL a,LL b,LL p)
{
    LL ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}


int main()
{
    LL p_,q_;
    LL p,q;
    char c;
    int t=0;
    while(scanf("%I64d%c%I64d",&p_,&c,&q_)!=EOF)
    {
        LL g=gcd(p_,q_);

        p=p_/g;
        q=q_/g;
        int m=0;
        while(q%2==0)
        {
            q/=2;
            m++;
        }
        int cnt;
        LL fac[1001];
        factor(euler_phi(q),fac,cnt);
        int i;
        for(i=0;i<cnt;i++)
        {
            if(qpow(2,fac[i],q)==1)
                break;
        }

        printf("Case #%d: %d,%I64d\n",++t,m+1,fac[i]);
    }

    return 0;
}