51_1037最长循环节 (miller rabin算法 pollard rho算法 原根)

1037 最长的循环节 V2

基准时间限制:1 秒 空间限制:131072 KB 分值: 320 难度:7级算法题
收藏
关注
正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数。
 
1/6= 0.1(6) 循环节长度为1
1/7= 0.(142857) 循环节长度为6
1/9= 0.(1)  循环节长度为1
Input
输入n(10 <= n <= 10^18)
Output
输出<=n的数中倒数循环节长度最长的那个数
Input示例
10
Output示例
7


主要用到了两个算法:miller rabin算法 pollard rho算法, 前者是种带概率性的判断质数,适用于较大数字的判断(概率性的), 后者用于大数的因式分解

模板代码:
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
 
const int Times=10;
const int N=5500;
 
using namespace std;
typedef long long LL;
 
LL ct,cnt,c,x,y;
LL fac[N],num[N],arr[N];
 
LL gcd(LL a,LL b)
{
    return b? gcd(b,a%b):a;
}
 
LL multi(LL a,LL b,LL m)
{
    LL ans=0;
    while(b)
    {
        if(b&1)
        {
            ans=(ans+a)%m;
            b--;
        }
        b>>=1;
        a=(a+a)%m;
    }
    return ans;
}
 
LL quick_mod(LL a,LL b,LL m)
{
    LL ans=1;
    a%=m;
    while(b)
    {
        if(b&1)
        {
            ans=multi(ans,a,m);
            b--;
        }
        b>>=1;
        a=multi(a,a,m);
    }
    return ans;
}
 
bool Miller_Rabin(LL n)
{
    if(n==2) return true;
    if(n<2||!(n&1)) return false;
    LL a,m=n-1,x,y;
    int k=0;
    while((m&1)==0)
    {
        k++;
        m>>=1;
    }
    for(int i=0; i<Times; i++)
    {
        a=rand()%(n-1)+1;
        x=quick_mod(a,m,n);
        for(int j=0; j<k; j++)
        {
            y=multi(x,x,n);
            if(y==1&&x!=1&&x!=n-1) return false;
            x=y;
        }
        if(y!=1) return false;
    }
    return true;
}
 
LL Pollard_rho(LL n,LL c)
{
    LL x,y,d,i=1,k=2;
    y=x=rand()%(n-1)+1;
    while(true)
    {
        i++;
        x=(multi(x,x,n)+c)%n;
        d=gcd((y-x+n)%n,n);
        if(1<d&&d<n) return d;
        if(y==x) return n;
        if(i==k)
        {
            y=x;
            k<<=1;
        }
    }
}
 
void find(LL n,int c)
{
    if(n==1) return;
    if(Miller_Rabin(n))
    {
        fac[ct++]=n;
        return ;
    }
    LL p=n;
    LL k=c;
    while(p>=n) p=Pollard_rho(p,c--);
    find(p,k);
    find(n/p,k);
}
 
void dfs(LL dept, LL product=1)
{
    if(dept==cnt)
    {
        arr[c++]=product;
        return;
    }
    for(int i=0; i<=num[dept]; i++)
    {
        dfs(dept+1,product);
        product*=fac[dept];
    }
}
 
void Solve(LL n)
{
    ct=0;
    find(n,120);
    sort(fac,fac+ct);
    num[0]=1;
    int k=1;
    for(int i=1; i<ct; i++)
    {
        if(fac[i]==fac[i-1])
            ++num[k-1];
        else
        {
            num[k]=1;
            fac[k++]=fac[i];
        }
    }
    cnt=k;
}
 
const int M=1000005;
bool prime[M];
int p[M];
int k1;
 
void isprime()
{
    k1=0;
    int i,j;
    memset(prime,true,sizeof(prime));
    for(i=2;i<M;i++)
    {
        if(prime[i])
        {
            p[k1++]=i;
            for(j=i+i;j<M;j+=i)
            {
                prime[j]=false;
            }
        }
    }
}
 
int main()
{
    LL n,t,record,tmp;
    isprime();
    while(cin>>n)
    {
        LL ans=-1;
        record=0;
        while(true)
        {
            tmp=1;
            if(Miller_Rabin(n))
            {
                Solve(n-1);
                c=0;
                dfs(0,1);
                sort(arr,arr+c);
                bool flag=0;
                for(int i=0; i<c; i++)
                {
                    if(quick_mod(10,arr[i],n)==1)
                    {
                        tmp=arr[i];
                        break;
                    }
                    if(i==c-2) flag=1;
                }
                if(flag)
                {
                    if(ans<tmp) record=n;
                    cout<<record<<endl;
                    break;
                }
            }
            else
            {
                bool flag=false;
                LL tmp1=(LL)sqrt(n*1.0);
                if(tmp1*tmp1==n&&Miller_Rabin(tmp1))
                {
                    x=tmp1;
                    y=2;
                    flag=true;
                }
                else
                {
                    LL cnt1=0,rea=n;
                    for(int i=0;i<k1;i++)
                    {
                        if(rea%p[i]==0)
                        {
                            x=p[i];
                            while(rea%p[i]==0)
                            {
                                rea/=p[i];
                                cnt1++;
                            }
                            break;
                        }
                    }
                    if(rea==1) flag=true;
                    y=cnt1;
                }
                if(flag)
                {
                    Solve(x-1);
                    c=0;
                    dfs(0,1);
                    sort(arr,arr+c);
                    bool flag=0;
                    for(int i=0; i<c; i++)
                    {
                        if(quick_mod(10,arr[i],x)==1)
                        {
                            tmp=1;
                            for(int j=0; j<y-1; j++)
                                tmp*=x;
                            tmp*=(x-1);
                            break;
                        }
                        if(i==c-2) flag=1;
                    }
                    if(flag)
                    {
                        if(ans<tmp)
                        {
                            ans=tmp;
                            record=n;
                        }
                    }
                }
            }
            n--;
        }
    }
    return 0;
}

 

posted @ 2016-05-04 00:14  W2W  阅读(586)  评论(0编辑  收藏  举报