Check If Digits Are Equal in String After Operations II

Check If Digits Are Equal in String After Operations II

You are given a string s consisting of digits. Perform the following operation repeatedly until the string has exactly two digits:

  • For each pair of consecutive digits in s, starting from the first digit, calculate a new digit as the sum of the two digits modulo 10.
  • Replace s with the sequence of newly calculated digits, maintaining the order in which they are computed.

Return true if the final two digits in s are the same; otherwise, return false.

 

Example 1:

Input: s = "3902"

Output: true

Explanation:

  • Initially, s = "3902"
  • First operation:
    • (s[0] + s[1]) % 10 = (3 + 9) % 10 = 2
    • (s[1] + s[2]) % 10 = (9 + 0) % 10 = 9
    • (s[2] + s[3]) % 10 = (0 + 2) % 10 = 2
    • s becomes "292"
  • Second operation:
    • (s[0] + s[1]) % 10 = (2 + 9) % 10 = 1
    • (s[1] + s[2]) % 10 = (9 + 2) % 10 = 1
    • s becomes "11"
  • Since the digits in "11" are the same, the output is true.

Example 2:

Input: s = "34789"

Output: false

Explanation:

  • Initially, s = "34789".
  • After the first operation, s = "7157".
  • After the second operation, s = "862".
  • After the third operation, s = "48".
  • Since '4' != '8', the output is false.

 

Constraints:

  • 3 <= s.length <= 105
  • s consists of only digits.

 

解题思路

  赛时一直惯性思维把模数认为是质数求组合数,结果样例一直过不了。然后 debug 很久才意识到 10 不是质数,但发现问题后还是不会算组合数模非质数的结果。今年 lc 明显比之前难了不少,我更是直接从 2700 俯冲到了 2400,再打多几场估计就掉到 2300 了。

  之前做过类似的,这类题在计算过程中不要把结果直接求和,而是用每一项表示出来。手推一下会发现每一项的系数其实就是杨辉三角的某一行,其中杨辉三角的第 i 行第 j 列的系数是 Cij(行列标号均从 0 开始)。

  由于最后会得到两个数,因此就需要分别计算 s0sn2 的结果 i=0n2Cn2isi,是否与 s1sn1 的结果 i=0n2Cn2isi+1 相同。

  但现在需要对组合数 Cab=a!b!(ab)!10,意味着需要求阶乘在模 10 意义下的乘法逆元,而 10 不是质数因此费马小定理不适用。又因为只有阶乘与模数 10 互质才存在逆元,因此很有可能是不存在逆元的!但组合数是一个整数,因此一定是有其他做法的。

  当模数不是质数时,有欧拉定理 xφ(m)1(modm),因此只要满足 gcd(x,m)=1,那么 x 的逆元就是 xφ(m)1(如果 m 是质数那么就变成费马小定理了)。因此对于一个数 x,当 m=10 时可以把质因子 25 提取出来,得到 x=x2c25c5 的形式,那么 xmodm 的结果就是 xφ(m)12c25c5modm

  因此对于组合数 Cab=a!b!(ab)!=xyz,其模 m=10 的结果就是 x2x25x5y2y25y5z2z25z5xyφ(m)1zφ(m)12x2y2z25x5y5z5(modm)。由于组合数是整数,x2y2z2x5y5z5 必然大于等于 0

  所以我们需要预处理 0n1 每个数的阶乘中,2 的质因子个数,5 的质因子个数,以及阶乘除去质因子 25 的结果。

  AC 代码如下,时间复杂度为 O(nlogn)

class Solution {
public:
    bool hasSameDigits(string s) {
        int n = s.size();
        vector<int> f(n), c2(n), c5(n);
        f[0] = 1;
        for (int i = 1; i < n; i++) {
            c2[i] = c2[i - 1];
            c5[i] = c5[i - 1];
            int t = i;
            while (t % 2 == 0) {
                c2[i]++;
                t /= 2;
            }
            while (t % 5 == 0) {
                c5[i]++;
                t /= 5;
            }
            f[i] = f[i - 1] * t % 10;
        }
        vector<int> inv(10, 1);
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 3; j++) {
                inv[i] = inv[i] * i % 10;
            }
        }
        vector<int> p2(n), p5(n);
        p2[0] = p5[0] = 1;
        for (int i = 1; i < n; i++) {
            p2[i] = p2[i - 1] * 2 % 10;
            p5[i] = p5[i - 1] * 5 % 10;
        }
        auto get = [&](int l, int r) {
            int ret = 0;
            for (int i = l; i <= r; i++) {
                ret = (ret + (s[i] - '0') * f[r - l] * inv[f[i - l]] * inv[f[r - i]] * p2[c2[r - l] - c2[i - l] - c2[r - i]] * p5[c5[r - l] - c5[i - l] - c5[r - i]]) % 10;
            }
            return ret;
        };
        return get(0, n - 2) == get(1, n - 1);
    }
};
class Solution {
public:
    bool hasSameDigits(string s) {
        int n = s.size();
        vector<int> p2(n), p5(n);
        p2[0] = p5[0] = 1;
        for (int i = 1; i < n; i++) {
            p2[i] = p2[i - 1] * 2 % 10;
            p5[i] = p5[i - 1] * 5 % 10;
        }
        int ret = s[0] - s[1], c = 1, c2 = 0, c5 = 0;
        auto get = [&](int &x, int p) {
            int ret = 0;
            while (x % p == 0) {
                ret++;
                x /= p;
            }
            return ret;
        };
        for (int i = 1; i + 1 < n; i++) {
            int a = n - 1 - i, b = i;
            c2 += get(a, 2) - get(b, 2);
            c5 += get(a, 5) - get(b, 5);
            c = c * a % 10;
            for (int i = 1; i < 10; i++) {
                if (i * b % 10 == 1) {
                    c = c * i % 10;
                    break;
                }
            }
            ret = (ret + c * (s[i] - s[i + 1]) * p2[c2] * p5[c5]) % 10;
        }
        return !ret;
    }
};

 

参考资料

  组合数模 10【力扣周赛 438】:https://www.bilibili.com/video/BV1hiAUeWEUG/

posted @   onlyblues  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-02-24 裁剪序列
2022-02-24 三体攻击
Web Analytics
点击右上角即可分享
微信分享提示