poj3696:同余方程,欧拉定理

感觉很不错的数学题,可惜又是看了题解才做出来的

题目大意:给定一个数n,找到8888....(x个8)这样的数中,满足能整除n的最小的x,若永远无法整除n 则输出0

做了这个题和后面的poj3358给我的感觉是这种复杂的数学题一定要哦上手去写,光想永远是想不出来的= =

做法:

基于欧拉定理:若gcd(a,m)=1 ,则满足 a^φ(m)  mod m=1, 即   a-1=k*m

88888(x个8)可以表示为 (10^x-1)/9*8,整除n

于是可以设 (10^x-1)/9*8=n*k ,移项得到 10^x-1=k*n*9/8

一看,刚好满足 a-1=k*m的形式,由于 n*9/8不一定为整数,所以我们令 m=n*9/gcd(n,8)  替代一个k=k*gcd(n,8)/8当作未知数

所以得到同余方程 10^x mod m=1

首先判断是否有解

由于 a mod m=gcd(a,m)的倍数 当gcd(10,m)>1时,显然无解,反之 则有解。

由欧拉定理只  φ(m)为此方程的一个解,但不一定是最小解

由于mod 乘法是有循环节的,由于 10^0 mod m=1成立 即对0,和φ(m)都成立,所以循环节要么是φ(m),要么是φ(m)的约数

所以我们只需要对φ(m)进行素因子分解,判断是否满足同余方程,就可以找到最小的解

代码:

#include <iostream>

#include <stdio.h>

#include<string.h>

#include<algorithm>

#include<string>

#include<ctype.h>

using namespace std;

#define I64d lld

long long gcd(long long a,long long b)

{

    return b?gcd(b,a%b):a;

}

long long fac[100000];

long long nfac;

long long phi(long long n)

{

    long long res=n;

    for(long long i=2;i*i<=n;i++)

    {

        if(n%i==0)

        {

            res=res-res/i;

            while(n%i==0)

                n/=i;

        }

    }

    if(n>1)

        res=res-res/n; //可能还有大于sqrt(n)的素因子

    return res;



}

long long random(long long n)

{

    return (long long)(rand()%(n-1)+1);

}

long long multi(long long a,long long b,long long m)//a*b%m

{

    long long res=0;

    while(b>0)

    {

        if(b&1)

            res=(res+a)%m;

        b>>=1;

        a=(a<<1)%m;

    }

    return res;

}

long long quickmod(long long a,long long b,long long m) //a^b%m

{

    long long res=1;

    while(b>0)

    {

        if(b&1)

            res=multi(res,a,m);

        b>>=1;

        a=multi(a,a,m);

    }

    return res;

}

int check(long long a,long long n,long long x,long long t)

{

    long long res=quickmod(a,x,n);

    long long last=res;

    for(int i=1;i<=t;i++)

    {

        res=multi(res,res,n);

        if(res==1&&last!=1&&last!=n-1) return 1;

        last=res;

    }

    if(res!=1) return 1;

    return 0;

}



int primetest(long long n)

{

    if(n<2)return 0;

    if(n==2)return 1;

    if((n&1)==0) return 0;

    long long x=n-1;

    long long t=0;

    while((x&1)==0){x>>=1;t++;}

    for(int i=0;i<20;i++)

    {

        long long a=random(n);

        if(check(a,n,x,t))

            return 0;

    }

    return 1;

}





long long pollardrho(long long n,long long c)

{

    long long x,y,d,i,k;

    i=1;k=2;

    x=random(n);

    y=x;

    while(1)

    {

        i++;

        x=(multi(x,x,n)+c)%n;

        long long tmp=y-x>=0?y-x:x-y;

        d=gcd(tmp,n);

        if(d>1&&d<n)

            return d;

        if(y==x)

            return n;

        if(i==k)

        {

            y=x;

            k+=k;

        }

    }

}

void findfac(long long n)

{

    if(n==1)

        return;

    if(primetest(n))

    {

        fac[nfac++]=n;

        return;

    }

    long long p=n;

    while(p>=n)

        p=pollardrho(n,random(n-1));

    findfac(p);

    findfac(n/p);

}

int main()

{

    long long n,m;

    int cas=0;

    while(scanf("%I64d",&n),n)

    {

        cas++;

        m=n*9/gcd(n,8);

        if(gcd(m,10)!=1)

        {

            printf("Case %d: %d\n",cas,0);

            continue;

        }

        long long p=phi(m);

        nfac=0;

        findfac(p);

        for(int i=0;i<nfac;i++)

        {

            p/=fac[i];

            if(quickmod(10,p,m)!=1)

                p*=fac[i];



        }

        printf("Case %d: %I64d\n",cas,p);

    }



    return 0;

}

 

你可能感兴趣的:(poj)