AcWing 202. 最幸运的数字
. 最幸运的数字
一、题目描述
是中国的幸运数字,如果一个数字的每一位都由构成则该数字被称作是幸运数字。
现在给定一个正整数 ,请问 至少多少个连在一起组成的正整数(即最小幸运数字)是的倍数。
输入格式
输入包含多组测试用例。
每组测试用例占一行,包含一个整数 。
当输入用例 时,表示输入终止,该用例无需处理。
输出格式
每组测试用例输出结果占一行。
结果为 Case i:
+一个整数 , 代表满足条件的最小幸运数字的位数。
如果满足条件的幸运数字不存在,则 。
数据范围
输入样例
8
11
16
0
输出样例
Case 1: 1
Case 2: 2
Case 3: 0
二、前导知识
用到了 个前导知识点:
1. 由 个 组成的数的公式是,比如 这种数。
2. 欧拉定理
若正整数互质,则
其中指欧拉函数值,与互质的数。
3. 欧拉定理推论
若正整数互质,则满足的 最小正整数解 是的约数。
反证法:假设该最小正整数 不是 的约数
则 ,
又
由 ② 式除以 ① 式得
故存在比 更小的正整数满足该式子,矛盾了
因此得证
4. 快速幂
int qmi(int a, int b, int p) {
int res = 1;
while (b) {
if (b & 1) res = res * a % p;
b >>= 1;
a = a * a % p;
}
return res;
}
5. 快速幂+快速乘
当模数的时候,在相乘的时候爆 了。
//快速乘
//时间复杂度:logn,乘法本来是O(1),这么干成了O(logN)了。
//优点:可以防止在LL*LL % MOD 过程中爆掉LL,可以将乘法分解成多步加法,在加的过程中不断取模。
int qmul(int a, int b, int mod) {
LL res = 0;
while (b) {
if (b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res;
}
//快速幂+快速乘
int qmi(int a, int b, int mod) {
int res = 1;
while (b) {
if (b & 1) res = qmul(res, a, mod); //调用龟速乘,原因是本题的数据范围是2*1e9,直接乘会爆掉LL,需要一路乘来一路取模
a = ksc(a, a, mod);
b >>= 1;
}
return res;
}
6. 配合快速幂
typedef __int128 LLL;
//快速幂+ LLL
int ksm(int a, int b, int mod) {
int res = 1;
while (b) {
if (b & 1) res = (LLL)res * a % mod;
a = (LLL)a * a % mod;
b >>= 1;
}
return res;
}
三、本题思路
题目实际上要我们求一个最小的正整数 ,满足
转化条件:
令,约分:
设
即:
最终变成 求解满足 的最小正整数
注释
既然是两个数的最大公约数,那么两个数都除以后,得到的两个新数,必然互质 (最大公约数的定义)
即:与是互质的,而还想是的整数倍
所以 一定是的因数,所以
四、欧拉定理+推论
欧拉定理: (其中)
这里的形式有点像欧拉定理,但是欧拉定理只是说是一个解,但不能保证 是满足等式的最小正整数!
由于我们学习过前导知识,知道如果想求最小正整数解,其实需要满足,我们只需要枚举每个的约数,找出满足条件的最小正整数即可。
五、实现代码(快速幂+快速乘)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
// 最大公约数
int gcd(int a, int b) {
if (b == 0) return a;
return b ? a : gcd(b, a % b);
}
// 快速乘
int ksc(int a, int b, int mod) {
int res = 0;
while (b) {
if (b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res;
}
// 快速幂+快速乘
int ksm(int a, int b, int mod) {
int res = 1;
while (b) {
if (b & 1) res = ksc(res, a, mod);
a = ksc(a, a, mod);
b >>= 1;
}
return res;
}
/**
* 功能:计算单个数字的欧拉函数值
* @param x
* @return
*/
int phi(int x) {
int 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;
}
signed main() {
int T = 1; // 准备输出Case i
int L;
while (cin >> L, L) {
int d = gcd(L, 8); // L和8的最大公约数 gcd(8,L)
int mod = 9 * L / d; // 公式推导得到的mod
int p = phi(mod); // 单个数字mod的欧拉函数值φ(mod)
int res = LONG_LONG_MAX; // 预求最小先设最大
if (gcd(mod, 10) > 1) // 判断mod和10是否互质,不互质:方程无解,输出0
res = 0;
else {
for (int d = 1; d * d <= p; d++) // 枚举φ(p)的每个小约数,到sqrt(φ(p))
if (p % d == 0) { // 如果d是约数,那么其实我们一次发现了两个约数: d 和 phi/d
// 这里与原来的质因子分解有一点点不同,因为那个只要枚举小于sqrt(n)的,并且 n %d==0,
// 就一定是它的小质数因子,本题不是这个意思。
// 本题的目标是找出所有因子,注意,不是小因子。
// 因为,小因子不见得能是方程的解,大因子不见得不是方程的解!!
// 对于它们,都有机会成为答案,需要全部讨论到!然后PK最小值即可!
// 如果这个约数d,满足 10 ^ d ≡ 1 (mod p) ,那么它有机会成为答案
if (ksm(10, d, mod) == 1) res = min(res, d); // 小约数
// 如果这个约数phi/d,满足 10 ^ (phi/d) ≡ 1 (mod p) ,那么它有机会成为答案
if (ksm(10, p / d, mod) == 1) res = min(res, p / d); // 大约数
}
}
// 输出
printf("Case %d: %lld\n", T++, res);
}
}
六、快速幂+
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
typedef unsigned __int128 INT128;
// 最大公约数
int gcd(int a, int b) {
if (b == 0) return a;
return b ? a : gcd(b, a % b);
}
// 快速幂+ INT128
int qmi(int a, int b, int mod) {
int res = 1;
while (b) {
if (b & 1) res = (INT128)res * a % mod;
a = (INT128)a * a % mod;
b >>= 1;
}
return res;
}
/**
* 功能:求单个数字的欧拉函数值
* @param x
* @return
*/
int phi(int x) {
int 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;
}
signed main() {
int T = 1; // 准备输出Case i
int L;
while (cin >> L, L) {
int d = gcd(L, 8); // L和8的最大公约数 gcd(8,L)
int mod = 9 * L / d; // 公式推导得到的mod
int p = phi(mod); // 单个数字mod的欧拉函数值φ(mod)
int res = LONG_LONG_MAX; // 预求最小先设最大
if (gcd(mod, 10) > 1) // 判断p和10是否互质,不互质:方程无解,输出0
res = 0;
else {
for (int d = 1; d * d <= p; d++) // 枚举φ(p)的每个小约数,到sqrt(φ(p))
if (p % d == 0) { // 如果d是约数,那么其实我们一次发现了两个约数: d 和 phi/d
// 这里与原来的质因子分解有一点点不同,因为那个只要枚举小于sqrt(n)的,并且 n %d==0,
// 就一定是它的小质数因子,本题不是这个意思。
// 本题的目标是找出所有因子,注意,不是小因子。
// 因为,小因子不见得能是方程的解,大因子不见得不是方程的解!!
// 对于它们,都有机会成为答案,需要全部讨论到!然后PK最小值即可!
// 如果这个约数d,满足 10 ^ d ≡ 1 (mod p) ,那么它有机会成为答案
if (qmi(10, d, mod) == 1) res = min(res, d); // 小约数
// 如果这个约数phi/d,满足 10 ^ (phi/d) ≡ 1 (mod p) ,那么它有机会成为答案
if (qmi(10, p / d, mod) == 1) res = min(res, p / d); // 大约数
}
}
// 输出
printf("Case %d: %lld\n", T++, res);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-05-28 linux磁盘IO读写性能优化