1. 程式人生 > >poj3696 The Luckiest number(質數,歐拉函數)

poj3696 The Luckiest number(質數,歐拉函數)

所有 ax1 str num stream 約數 main 滿足 href

poj

題意:給定一個正整數L(\(L<=2*10^9\)),求至少多少個8連在一起組成的正整數是L的倍數?

分析:x個8連在一起的正整數可寫作\(8*(10^x-1)/9\),於是題目轉換為了求一個最小的x,使得\(L|8*(10^x-1)/9\),整理一下式子得\(9*L|8*(10^x-1)\),設\(d=gcd(9*L,8)\).

所以有\(9L/d\)與8/d互質,所以式子等價於\((9L/d)|10^x-1\),所以\(10^x≡1(mod(9L/d))\)

若正整數a,n互質,則滿足\(a^x≡1(mod(m))\)的最小正整數\(x\)\(phi(n)\)的約數.(證明略)

所以我們可以求出\(phi(9L/d)\)
,枚舉它的所有約數,用快速冪判斷是否滿足條件.

#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
ll gcd(ll a,ll b){
    if(b==0)return a;
    return gcd(b,a%b);
}
ll quickmul(ll a,ll b,ll c){
    ll cnt=0;
    while(b){
        if(b&1)cnt=(cnt+a)%c;
        a=(a+a)%c;
        b>>=1;
    }
    return cnt;
}//快速乘,好像沒什麽必要
ll power(ll a,ll b,ll c){
    ll cnt=1;
    while(b){
        if(b&1)cnt=quickmul(cnt,a,c)%c;
        a=quickmul(a,a,c)%c;
        b>>=1;
    }
    return cnt;
}
ll get_phi(ll n){
    ll cnt=n;
    for(ll i=2;i*i<=n;++i){
        if(n%i==0)cnt=cnt/i*(i-1);
        while(n%i==0)n/=i;
    }
    if(n!=1)cnt=cnt/n*(n-1);
    return cnt;
}
int main(){
    ll L,T=0;
    while(scanf("%lld",&L)&&L!=0){  
        ++T;
        ll n=9*L/gcd(1ll*8,1ll*9*L);ll x=get_phi(n);
        if(gcd(10,n)!=1){printf("Case %d: 0\n",T);continue;}
        int bj=0;
        for(ll i=1;i*i<=x;i++)
            if(x%i==0&&power(10,i,n)==1){
                printf("Case %lld: %lld\n",T,i);
                bj=1;break;
        }
        if(bj)continue;
        for(ll i=sqrt(1.0*x);i>=1;i--)
            if(x%i==0&&power(10,x/i,n)==1){
                printf("Case %lld: %lld\n",T,x/i);
                break;
            }
    }
    return 0;
}

poj3696 The Luckiest number(質數,歐拉函數)