POJ 3696 The Luckiest number(欧拉定理妙妙妙)

题目描述

传送门

题目大意:给你一个数L(1≤L≤2,000,000,000),求一个最小的全部由8组成的是L倍数的十进制数,输出它的位数,如果无解输出0。


题解

这是一道如果我不看题解就永远也想不到的题。

一个全部由8组成的数可以这样表示

89(10x1)

其中 x 为正整数

然后我们要求的就是一个这样的x,使得存在一个正整数 k ,满足

89(10x1)=kL

8(10x1)=9kL

d=(8,9L)=(8,L),p=8d,q=9Ld ,有

p(10x1)=kq

此时 p q已经互质,故 q|(10x1) ,画画柿子就是

10x1(mod q)

这个东西像什么?欧拉定理!当 (10,q)=1 x=φ(q) 就是一组解。

不一定是最小的解怎么办?枚举 φ(q) 的约数看看是否可行。如果 10min=1 ,而 10φ(q)=1 ,必有 min|φ(q) 相当于所有周期都是最小周期的倍数
注意要找约数而不是质因数,没有为什么。

注意这里两个long long相乘会爆,用快速乘就行了(就是将一个数分解成二进制按位累加而已)。

10 q <script type="math/tex" id="MathJax-Element-20">q</script>不互质时显然无解。

时间复杂度:O(跑得过)。


代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;

typedef long long LL;

int Case;
LL L, Phi, d, q, ans;

LL Gcd(LL x, LL y){
    if(!y)  return x;
    return Gcd(y, x % y);
}

LL Calc(LL x){
    LL res = x;
    for(LL i = 2; i * i <= x; i++)
        if(x % i == 0){
            res /= i;
            res *= i - 1LL;
            while(x % i == 0)  x /= i;
        }

    if(x != 1){
        res /= x;
        res *= x - 1LL;
    }
    return res;
}

LL Muti(LL x, LL y, LL MOD){
    LL res = 0LL;
    while(y){
        if(y & 1)  res = (res + x) % MOD;
        x = (x << 1) % MOD;
        y >>= 1LL;
    }
    return res;
}

LL Pow(LL x, LL y, LL MOD){
    LL res = 1LL;
    while(y){
        if(y & 1)  res = Muti(res, x, MOD);
        x = Muti(x, x, MOD);
        y >>= 1LL;
    }
    return res;
}

int main(){

    while(~ scanf("%I64d", &L) && L){

        d = Gcd(8LL, L);
        q = 9 * L / d;

        if(q % 2 == 0 || q % 5 == 0)  ans = 0LL;

        else{
            ans = Phi = Calc(q);
            for(LL i = 1; i * i <= Phi; i++){
                if(Phi % i == 0){
                    if(Pow(10LL, i, q) == 1LL)  ans = min(ans, i);
                    if(i != Phi/i && Pow(10LL, Phi/i, q) == 1LL)  ans = min(ans, Phi/i);
                }
            }
        }

        printf("Case %d: %I64d\n", ++Case, ans);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值