【POJ 3696】The Luckiest Number

题目描述

至少多少个 8 8 连在一起组成的数是 l(l2×109) 的倍数。

算法分析

x x 8 连在一起组成的数是 l l 的倍数,则表示为 l|8×(10x1)9

转化一下就是 9×l|8×(10x1) 9 × l | 8 × ( 10 x − 1 ) ,接下来怎么转化?

9×l 9 × l 10x1 10 x − 1 的约数吗?不一定,还需要从重去除 l l 8 分解质因数后的公共部分,即 gcd(8,l) g c d ( 8 , l )

所以上式就变成 9×lgcd(8,l)|10x1 9 × l g c d ( 8 , l ) | 10 x − 1 ,即 10x1(mod9×lgcd(8,l)) 10 x ≡ 1 ( mod 9 × l g c d ( 8 , l ) )

有一个结论:

  • 10x1(modp) 10 x ≡ 1 ( mod p ) ,满足条件的最小的 x x 一定是 ϕ(p) 的约数。(反证法)

然后就可以求出 ϕ(9×lgcd(8,l)) ϕ ( 9 × l g c d ( 8 , l ) ) 的值,枚举它的所有约数,使用快速幂一一判断是否满足条件即可。

注意开 64 64 位整数,计算快速幂的时候中间结果会超过 64 64 位整数范围,因此需要利用之前本博客中介绍的技巧计算。

代码实现

#include <cstdio>
#include <climits>
#include <algorithm>
typedef long long int ll;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
inline ll eular(ll n) {
    ll ans=n;
    for(ll i=2;i*i<=n;++i) {
        if(n%i==0) {
            ans=ans/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) ans=ans/n*(n-1);
    return ans;
}
ll p;
ll mul(ll a,ll b) {
    ll temp=(long double)a*b/p;
    ll ans=a*b-temp*p;
    if(ans>=p) ans-=p;
    if(ans<0) ans+=p;
    return ans;
}
ll pow(ll n,ll k) {
    ll ans=1;
    while(k) {
        if(k&1) ans=mul(ans,n);
        n=mul(n,n);k>>=1;
    }
    return ans;
}
int main() {
    ll l;int kase=0;
    while(scanf("%lld",&l)==1&&l) {
        p=l*9/gcd(8,l);ll n=eular(p),ans=1LL<<60;
        for(ll i=1;i*i<=n;++i) {
            if(n%i==0) {
                if(pow(10,i)==1) {ans=i;break;}
                else if(i*i!=n&&pow(10,n/i)==1) ans=std::min(ans,n/i);
            }
        }
        printf("Case %d: %lld\n",++kase,ans==1LL<<60?0:ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值