NKOJ3685 8数

问题描述

给一个正整数N,问是否存在N的倍数M,且M的各个位全部由数字8组成,如果存在多个取最小的M;并输出M由几个8组成。

输入格式

一行,一个整数N

输出格式

一行一个整数,表示所求的结果
如果无解,输出0

由题得:M==t*N.

由于M==8*11……1,设n==11……1有k位,则n可以表示为:n==10^(k-1)+10^(k-2)+……+10^0.

因为这是一个等比数列,公比q==10,所以根据等比数列求和公式,n==(10^k-1)/9.

带入最开始的式子M==t*N,得到:M==8*n==8*(10^k-1)/9==t*N,移项,得:8*(10^k-1)==9*t*N.

继续化简,由于8和9*t是已知数,所以对它们约分。设d==gcd(8,9*t),则(8/d)*(10^k-1)==(9*t/d)*N.

由于8/d和9*t/d互质,所以(10^k-1)中含因子9*t/d。令m==9*t/d,则(10^k-1)%m==0,所以10^k%m==1,即10^k与m互质.

根据欧拉定理,当a与b互质时,a^phi(b)%b==1.由于10^k%m==1,所以k的一个解就是phi(m).**

幂运算取模有循环节(尽管我并不知道这是为何)。对于10^phi(m)%m==1,设循环节长度为s。显然,10^0%m==1,10^(0+i*s)%m==1即10^(i*s)%m==1。所以,phi(m)==i*s,由于我们实际上不知道s的值,所以问题就变成了求phi(m)内的因数(把phi(m)的因数往式子里面带,找出最小的符合条件的因数)。

总结

1.当数字由若干个重复的数字组成时,可用位数来表示这个数(指数形式)

2.如果(a-1)%p==0,那么a%p==1

3.幂运算取模有循环节;可以通过这一性质对幂运算降幂

#include
#include
#include
#include
#define ll long long 
using namespace std;
ll qui(ll a,ll b,ll c){
    ll ans=0;
    while(b){
        if(b&1)ans=(ans+a)%c;
        b>>=1,a=(a<<1)%c;
    }
    return ans;
} 
ll getPhi(ll n){
    ll ans=n,a=n;
    for(ll i=2;i*i<=a;i++)
        if(a%i==0){
            ans-=ans/i;
            while(a%i==0)a/=i;
        }
    if(a>1)ans-=ans/a;
    return ans;
}
ll mont(ll a,ll b,ll c){
    ll ans=1;a%=c;
    while(b){
        if(b&1)ans=qui(ans,a,c);
        b>>=1,a=qui(a,a,c);
    }
    return ans;
}
int main(){
    ll n,m,p,pp,ans=2e9+1;scanf("%lld",&n);
    m=(9*n)/__gcd(8LL,9*n);
    if(__gcd(10LL,m)!=1){printf("0");return 0;} 
    p=getPhi(m),pp=sqrt(p)+0.5;
    for(ll i=1;i<=pp;i++)
        if(p%i==0){
            if(mont(10,i,m)==1){
                printf("%lld",i);
                return 0;
            }
            if(mont(10,p/i,m)==1)ans=min(ans,p/i);
        }
    printf("%lld",ans);return 0;
}

你可能感兴趣的:(题解,数论)