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;
}

 

posted @ 2014-09-18 18:54  PlasticSpirit  阅读(788)  评论(0编辑  收藏  举报