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 istrue
.
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 isfalse
.
Constraints:
3 <= s.length <= 105
s
consists of only digits.
解题思路
赛时一直惯性思维把模数认为是质数求组合数,结果样例一直过不了。然后 debug 很久才意识到 10 不是质数,但发现问题后还是不会算组合数模非质数的结果。今年 lc 明显比之前难了不少,我更是直接从 2700 俯冲到了 2400,再打多几场估计就掉到 2300 了。
之前做过类似的,这类题在计算过程中不要把结果直接求和,而是用每一项表示出来。手推一下会发现每一项的系数其实就是杨辉三角的某一行,其中杨辉三角的第 $i$ 行第 $j$ 列的系数是 $C_{i}^{j}$(行列标号均从 $0$ 开始)。
由于最后会得到两个数,因此就需要分别计算 $s_0 \sim s_{n-2}$ 的结果 $\sum\limits_{i=0}^{n-2}{C_{n-2}^{i} s_i}$,是否与 $s_{1} \sim s_{n-1}$ 的结果 $\sum\limits_{i=0}^{n-2}{C_{n-2}^{i} s_{i+1}}$ 相同。
但现在需要对组合数 $C_{a}^{b} = \frac{a!}{b!(a-b)!}$ 模 $10$,意味着需要求阶乘在模 $10$ 意义下的乘法逆元,而 $10$ 不是质数因此费马小定理不适用。又因为只有阶乘与模数 $10$ 互质才存在逆元,因此很有可能是不存在逆元的!但组合数是一个整数,因此一定是有其他做法的。
当模数不是质数时,有欧拉定理 $x^{\varphi(m)} \equiv 1 \pmod{m}$,因此只要满足 $\gcd(x,m)=1$,那么 $x$ 的逆元就是 $x^{\varphi(m)-1}$(如果 $m$ 是质数那么就变成费马小定理了)。因此对于一个数 $x$,当 $m=10$ 时可以把质因子 $2$ 和 $5$ 提取出来,得到 $x = x' 2^{c_2} 5^{c_5}$ 的形式,那么 $x \bmod m$ 的结果就是 ${x'}^{\varphi(m)-1} 2^{c_2} 5^{c_5} \bmod m$。
因此对于组合数 $C_{a}{b} = \frac{a!}{b!(a-b)!} = \frac{x}{yz}$,其模 $m=10$ 的结果就是 $\frac{x' 2^{x_2} 5^{x_5}}{y' 2^{y_2} 5^{y_5} \cdot z' 2^{z_2} 5^{z_5}} \equiv x' \, {y'}^{\varphi(m)-1} \, {z'}^{\varphi(m)-1} \, 2^{x_2-y_2-z_2} \, 5^{x_5-y_5-z_5} \pmod{m}$。由于组合数是整数,$x_2-y_2-z_2$ 和 $x_5-y_5-z_5$ 必然大于等于 $0$。
所以我们需要预处理 $0 \sim n-1$ 每个数的阶乘中,$2$ 的质因子个数,$5$ 的质因子个数,以及阶乘除去质因子 $2$ 和 $5$ 的结果。
AC 代码如下,时间复杂度为 $O(n \log{n})$:
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/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18733598