• AcWing 202. 最幸运的数字


    题目传送门

    一、总结

    用到了 \(6\)个知识点:

    1. 由 \(x\)\(y\) 组成的数的公式是\(\large \displaystyle y*\frac{10^x-1}{9}\)。比如 \(88888888\)这种数。
    证明:
    \(\large \displaystyle \underbrace{8...8}_{x}=8 \times \underbrace{1...1}_{x}=8 \times \frac{9...9}{9}=8 \times \frac{10^x-1}{9}\)

    2. 欧拉定理
    \(a, n\)为正整数,且\(a,n\)互质 ,则 $$\large a^{φ(n)}≡1(mod \ n)$$

    其中\(\phi(n)\)指欧拉函数值。如果\(a,n\)不互质,则方程无解。

    3. 欧拉定理推论
    若正整数\(a,n\)互质,则满足\(a^x \equiv 1 \ (mod \ n)\)的最小正整数 \(x_0\)\(\phi(n)\)的约数。

    4. 快速幂

    // 原生快速幂 (a^k)%p
    LL qmi(LL a, LL k, LL p) {
        LL res = 1;
        while (k) {
            if (k & 1) res = res * a % p;
            k >>= 1;
            a =  a * a % p;
        }
        return res;
    }
    

    5. 快速幂+龟速乘
    当模数\(>1e9\)的时候,在相乘的时候爆\(long\) \(long\)了。
    参考网址:https://blog.csdn.net/cyan_rose/article/details/83065026

    //龟速乘
    //时间复杂度:logn,乘法本来是O(1),这么干成了O(logN)了。
    //优点:可以防止在LL*LL % MOD 过程中爆掉LL,可以将乘法分解成多步加法,在加的过程中不断取模。
    LL qmul(LL a, LL k, LL b) {
        LL res = 0;
        while (k) {
            if (k & 1) res = (res + a) % b;
            a = (a + a) % b;
            k >>= 1;
        }
        return res;
    }
    
    //快速幂+龟速乘
    LL qmi(LL a, LL k, LL b) {
        LL res = 1;
        while (k) {
            if (k & 1) res = qmul(res, a, b); //调用龟速乘,原因是本题的数据范围是2*1e9,直接乘会爆掉LL,需要一路乘来一路取模
            a = qmul(a, a, b);
            k >>= 1;
        }
        return res;
    }
    

    6. INT128配合快速幂

    //下面的办法可以用来测试编译器是不是支持 LLL
    typedef __int128 LLL;
    
    //快速幂+  LLL
    LL qmi(LL a, LL k, LL b) {
        LL res = 1;
        while (k) {
            if (k & 1) res = (LLL)res * a % b;
            a = (LLL)a * a % b;
            k >>= 1;
        }
        return res;
    }
    
    

    二、推导过程

    题目实际上要我们求一个最小的正整数 \(x\),满足 \(\large \displaystyle L|8*\frac{10^x-1}{9}\)

    我们来转化一下这个限制条件:

    \[\large \displaystyle \Leftrightarrow 9*L | 8(10^x-1) \]

    \(\large \displaystyle d=gcd(L,8)\),那么约分:

    \[\large \displaystyle \Leftrightarrow \frac{9*L}{d} | 10^x-1 \ \ \ \ ① \]

    \[\large \displaystyle \Leftrightarrow 10^x-1 \equiv 0 \ (mod \ \frac{9*L}{d}) \]

    \[\large \displaystyle \Leftrightarrow 10^x \equiv 1 \ (mod \ \frac{9*L}{d}) \]

    \(\large \displaystyle p=\frac{9*L}{d}\)

    即:

    \[\large \displaystyle \Leftrightarrow 10^x \equiv 1 \ (mod \ p) \]

    最终变成求解满足 \(\large \displaystyle 10^x≡1(mod \ p)\) 的最小正整数 \(x\)

    注释 ① :(一开始我看不懂这一步,解释一下\(qwq\))

    • $\large \displaystyle gcd(8,9)=1 \Rightarrow d=gcd(9L,8)=gcd(8,L) $ (参考黄海整理的最大公约数性质\(4\))
    • \(d\)既然是两个数的最大公约数,那么两个数都除以\(d\)后,得到的两个新数,必须互质 (这是最大公约数的定义)
      即:\(\large \displaystyle \frac{9*L}{d}\)\(\large \displaystyle \frac{8}{d}\)是互质的,而\(\large \displaystyle 10^x-1\)还想是\(\large \displaystyle \frac{9*L}{d}\)的整数倍
      所以 \(\large \displaystyle \frac{9*L}{d}\)一定是\(\large \displaystyle 10^x-1\)的因数,所以\(\large \displaystyle \Leftrightarrow \frac{9*L}{d} | 10^x-1\)

    三、欧拉定理

    欧拉定理: \(\large \displaystyle a^{φ(n)}≡1(mod \ n)\)(其中\(\large \displaystyle gcd(a,n)=1\))

    这里的形式有点像欧拉定理,\(\large a^{\phi(c)}\equiv 1 (mod \ p)\)但是欧拉定理只是说\(\large φ(n)\)是一个解,但不能保证 \(\large φ(n)\) 是满足等式的最小正整数!

    由于我们学习过前导知识,知道如果想求最小正整数解\(\large x\),其实需要满足\(\large x|\phi(c)\),我们只需要枚举每个\(\large \phi(c)\)的约数,找出满足条件的最小正整数\(\large x\)即可。

    四、实现代码(快速幂+龟速乘)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    //最大公约数
    int gcd(int a, int b) {
        if (b == 0) return a;
        return b ? a : gcd(b, a % b);
    }
    
    //龟速乘
    LL qmul(LL a, LL k, LL b) {
        LL res = 0;
        while (k) {
            if (k & 1) res = (res + a) % b;
            a = (a + a) % b;
            k >>= 1;
        }
        return res;
    }
    
    //快速幂+龟速乘
    LL qmi(LL a, LL k, LL b) {
        LL res = 1;
        while (k) {
            if (k & 1) res = qmul(res, a, b);
            a = qmul(a, a, b);
            k >>= 1;
        }
        return res;
    }
    
    /**
     * 功能:欧拉函数
     * @param x
     * @return
     */
    LL get_euler(LL x) {
        LL res = x;
        for (int i = 2; i <= x / i; i++)
            if (x % i == 0) {
                res = res / i * (i - 1);
                while (x % i == 0) x /= i;
            }
        if (x > 1) res = res / x * (x - 1);
        return res;
    }
    
    int main() {
        int T = 1; //准备输出Case i
        LL L;
        while (cin >> L, L) {
            int d = gcd(L, 8);     // L和8的最大公约数 gcd(8,L)
            LL p = 9 * L / d;      // 公式推导得到的p
            LL phi = get_euler(p); // 单个数字p的欧拉函数值φ(p)
            LL res = LONG_LONG_MAX; //预求最小先设最大
    
            if (gcd(p, 10) > 1) //判断p和10是否互质,不互质:方程无解,输出0
                res = 0;
            else {
                for (LL d = 1; d * d <= phi; d++) //枚举φ(p)的每个小约数,到sqrt(φ(p))
                    if (phi % d == 0) {           //如果d是约数,那么其实我们一次发现了两个约数: d 和 phi/d
                        //这里与原来的质因子分解有一点点不同,因为那个只要枚举小于sqrt(n)的,并且 n %d==0,
                        //就一定是它的小质数因子,本题不是这个意思。
                        //本题的目标是找出所有因子,注意,不是小因子。
                        //因为,小因子不见得能是方程的解,大因子不见得不是方程的解!!
                        //对于它们,都有机会成为答案,需要全部讨论到!然后PK最小值即可!
                        //如果这个约数d,满足 10 ^ d ≡ 1 (mod p) ,那么它有机会成为答案
                        if (qmi(10, d, p) == 1) res = min(res, d);             //小约数
                        //如果这个约数phi/d,满足 10 ^ (phi/d) ≡ 1 (mod p) ,那么它有机会成为答案
                        if (qmi(10, phi / d, p) == 1) res = min(res, phi / d); //大约数
                    }
            }
            //输出
            printf("Case %d: %lld\n", T++, res);
        }
        return 0;
    }
    

    五、快速幂+__int128

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    //下面的办法可以用来测试编译器是不是支持 LLL
    typedef unsigned __int128 LLL;
    
    //最大公约数
    int gcd(int a, int b) {
        if (b == 0) return a;
        return b ? a : gcd(b, a % b);
    }
    
    //快速幂+  LLL
    LL qmi(LL a, LL k, LL b) {
        LL res = 1;
        while (k) {
            if (k & 1) res = (LLL)res * a % b;
            a = (LLL)a * a % b;
            k >>= 1;
        }
        return res;
    }
    
    /**
     * 功能:欧拉函数
     * @param x
     * @return
     */
    LL get_euler(LL x) {
        LL res = x;
        for (int i = 2; i <= x / i; i++)
            if (x % i == 0) {
                res = res / i * (i - 1);
                while (x % i == 0) x /= i;
            }
        if (x > 1) res = res / x * (x - 1);
        return res;
    }
    
    int main() {
        int T = 1; //准备输出Case i
        LL L;
        while (cin >> L, L) {
            int d = gcd(L, 8);      // L和8的最大公约数 gcd(8,L)
            LL p = 9 * L / d;       // 公式推导得到的p
            LL phi = get_euler(p);  // 单个数字p的欧拉函数值φ(p)
            LL res = LONG_LONG_MAX; //预求最小先设最大
    
            if (gcd(p, 10) > 1) //判断p和10是否互质,不互质:方程无解,输出0
                res = 0;
            else {
                for (LL d = 1; d * d <= phi; d++) //枚举φ(p)的每个小约数,到sqrt(φ(p))
                    if (phi % d == 0) {           //如果d是约数,那么其实我们一次发现了两个约数: d 和 phi/d
                        //这里与原来的质因子分解有一点点不同,因为那个只要枚举小于sqrt(n)的,并且 n %d==0,
                        //就一定是它的小质数因子,本题不是这个意思。
                        //本题的目标是找出所有因子,注意,不是小因子。
                        //因为,小因子不见得能是方程的解,大因子不见得不是方程的解!!
                        //对于它们,都有机会成为答案,需要全部讨论到!然后PK最小值即可!
                        //如果这个约数d,满足 10 ^ d ≡ 1 (mod p) ,那么它有机会成为答案
                        if (qmi(10, d, p) == 1) res = min(res, d); //小约数
                        //如果这个约数phi/d,满足 10 ^ (phi/d) ≡ 1 (mod p) ,那么它有机会成为答案
                        if (qmi(10, phi / d, p) == 1) res = min(res, phi / d); //大约数
                    }
            }
            //输出
            printf("Case %d: %lld\n", T++, res);
        }
        return 0;
    }
    

    参考网址:https://www.acwing.com/solution/content/47979/

  • 相关阅读:
    handle/hmodule/hinstance/hwnd区别
    How to control progress bar setup made by WIX
    C#定制并发送HTML邮件
    如何添加WPF,SilverLight控件到ToolBox
    【FWD】Windows Azure Table Storage vs. Windows SQL Azure
    MSBuild failed after add a new configuration
    .NET 下各种Resource的读取方式
    杨辉三角算法改进
    代码生成技术
    回家的美丽
  • 原文地址:https://www.cnblogs.com/littlehb/p/16320810.html
Copyright © 2020-2023  润新知