• 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
    ",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
    ",cas,p);
        }
    
        return 0;
    }
  • 相关阅读:
    poj 3070 矩阵快速幂模板
    poj3207 2-SAT入门
    poj 3683 2-SAT入门
    2-SAT开坑
    poj 1442 名次树
    hdu 3068 最长回文子串 TLE
    poj 3261 二分答案+后缀数组 求至少出现k次的最长重复子序列
    poj 1743 二分答案+后缀数组 求不重叠的最长重复子串
    后缀数组笔记
    poj2774 后缀数组 求最长公共子串
  • 原文地址:https://www.cnblogs.com/oneshot/p/3979847.html
Copyright © 2020-2023  润新知