欧拉定理+同余——最幸运的数字

最幸运的数字

8是中国的幸运数字,如果一个数字的每一位都由8构成则该数字被称作是幸运数字。

现在给定一个正整数L,请问至少多少个8连在一起组成的正整数(即最小幸运数字)是L的倍数。

输入格式
输入包含多组测试用例。

每组测试用例占一行,包含一个整数L。

当输入用例L=0时,表示输入终止,该用例无需处理。

输出格式
每组测试用例输出结果占一行。

结果为“Case 1: ”+一个整数N,N代表满足条件的最小幸运数字的位数。

如果满足条件的幸运数字不存在,则N=0。

数据范围
1 ≤ L ≤ 2 ∗ 1 0 9 1≤L≤2∗10^9 1L2109
输入样例:
8
11
16
0
输出样例:
Case 1: 1
Case 2: 2
Case 3: 0

题解:

题目好是好,但是也是太恶心了吧。想到了正解,谁又想到Long long也爆了呢。
正解:
8.....8 = 8 ∗ 1....1 = 8 ∗ 9....9 9 = 8 9 ∗ ( 1 0 x − 1 ) 8.....8=8*1....1=8*\frac{9....9}{9}=\frac{8}{9}*(10^x-1) 8.....8=81....1=899....9=98(10x1)
上述的数字是L的倍数等价于L能被他们整除,所以L是他们的约数
L ∣ 8 9 ∗ 1 0 x − 1 L|\frac{8}{9}*10^x-1 L9810x1
L ∗ 9 ∣ 8 ∗ 1 0 x − 1 L*9|8*10^x-1 L9810x1
因为8和9互质所以我们要约掉8就是除以 ( L , 8 ) [ ( a , b ) 表 示 a , b 的 g c d ] (L,8)[(a,b)表示a,b的gcd] (L,8)[(a,b)a,bgcd]
所以化简得到
L 1 = 1 0 x − 1 。 L 1 = 9 ∗ l ( L , 8 ) L_1=10^x-1。L_1=\frac{9*l}{(L,8)} L1=10x1L1=(L,8)9l
等价 1 0 x ≡ 1 ( m o d L 1 ) 10^x≡ 1(mod L_1) 10x1(modL1)不会打同余符号
这个和我们欧拉定理是不是很像。我们把x换成 p h i ( L 1 ) phi(L_1) phi(L1)就是我们欧拉定理了。
根据欧拉定理我们知道,只有当我们 L 1 和 10 互 质 的 时 候 才 是 有 解 的 。 L_1和10互质的时候才是有解的。 L110
并且这里我们的最小解是 p h i ( L 1 ) phi(L_1) phi(L1)的最小约数。
证明如下:
利用反正法,最小解X不是我们的最小约数,则 p h i ( L 1 ) = x ∗ k + r ( 1 < r < x ) phi(L_1)=x*k+r(1<r<x) phi(L1)=xk+r(1<r<x)
整理上述条件
1 0 x ≡ 1 ( m o d L 1 ) 10^x≡ 1(mod L_1) 10x1(modL1)
所以 1 0 q x ≡ 1 ( m o d L 1 ) 10^{qx}≡ 1(mod L_1) 10qx1(modL1)
1 0 p h i ( L 1 ) ≡ 1 ( m o d L 1 ) 10^{phi(L_1)}≡ 1(mod L_1) 10phi(L1)1(modL1) 可以得到
1 0 r ≡ 1 ( m o d L 1 ) 10^{r}≡ 1(mod L_1) 10r1(modL1)
因为r<x所以于假设矛盾。即最小解x是我们的最小约数。
所以答案也就变成了在 p h i ( L 1 ) phi(L_1) phi(L1)的约数中找一个最小的。
最后记得用龟速乘。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int qmul(int a, int k, int b)
{
    int res = 0;
    while (k)
    {
        if (k & 1) res = (res + a) % b;
        a = (a + a) % b;
        k >>= 1;
    }
    return res;
}
int q_pow(int a,int k,int b)
{
    int res=1;
    while(k){
        if(k&1) res=qmul(res,a,b);
        a=qmul(a,a,b);
        k>>=1;
    }
    return  res;
}
int get_euler(int c)
{
    int res=c;
    for(int i=2;i<=c/i;i++){
        if(c%i==0){
            while(c%i==0) c/=i;
            res=res/i*(i-1);
        }
    }
    if(c>1) res=res/c*(c-1);
    return res;
}
signed main()
{
    int T=1;
    long long n;
    while(cin>>n,n){
        int d=1;
        while(n%(d*2)==0&&d * 2 <= 8) d*=2;
        int C=9*n/d;
        int res=1e18;
        if(C%2==0||C%5==0) res=0;
        int phi=get_euler(C);
        for(int i=1;i*i<=phi;i++){
            if(phi%i==0){
                if(q_pow(10,i,C)==1) res=min(res,i);
                if(q_pow(10,phi/i,C)==1) res=min(res,phi/i);
            }
        }
        printf("Case %d: %lld\n", T ++, res);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值