数论(同余方程) - The Luckiest number - POJ 3696
题意:
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 1≤L≤2×109
输入样例:
8
11
16
0
输出样例:
Case 1: 1
Case 2: 2
Case 3: 0
分析:
长度为x的,由同一个数字组成的数,如何表示成关于x的函数形式?
以 x 个 8 为 例 : 以x个8为例: 以x个8为例:
888...888 ⏟ x 个 8 = 8 × 111...111 ⏟ x 个 1 = 8 × 999...999 9 = 8 9 ( 1 0 x − 1 ) 。 \underbrace{888...888}_{x个8}=8×\underbrace{111...111}_{x个1}=8×\frac{999...999}{9}=\frac{8}{9}(10^x-1)。 x个8 888...888=8×x个1 111...111=8×9999...999=98(10x−1)。
本 题 要 求 888...888 ≡ 0 ( m o d L ) 即 8 9 ( 1 0 x − 1 ) ≡ 0 ( m o d L ) 的 关 于 x 的 最 小 正 整 数 解 , 本题要求888...888≡0(mod\ L)\ 即\ \frac{8}{9}(10^x-1)≡0(mod\ L)的关于x的最小正整数解, 本题要求888...888≡0(mod L) 即 98(10x−1)≡0(mod L)的关于x的最小正整数解,
先 求 一 组 解 ( x 0 , y 0 ) , 先求一组解(x_0,y_0), 先求一组解(x0,y0),
< = > 8 ( 1 0 x − 1 ) ≡ 0 ( m o d 9 L ) , <=>8(10^x-1)≡0(mod\ 9L), <=>8(10x−1)≡0(mod 9L),
< = > 1 0 x − 1 ≡ 0 ( m o d 9 L g c d ( L , 8 ) ) , ( 因 为 9 和 8 互 质 ) <=>10^x-1≡0(mod\ \frac{9L}{gcd(L,8)}),(因为9和8互质) <=>10x−1≡0(mod gcd(L,8)9L),(因为9和8互质)
< = > 1 0 x ≡ 1 ( m o d 9 L g c d ( L , 8 ) ) <=>10^x≡1(mod\ \frac{9L}{gcd(L,8)}) <=>10x≡1(mod gcd(L,8)9L)
记 C = 9 L g c d ( L , 8 ) , 由 于 x 与 C 不 一 定 互 质 , 故 不 满 足 用 费 马 小 定 理 使 用 的 条 件 , 记C= \frac{9L}{gcd(L,8)},由于x与C不一定互质,故不满足用费马小定理使用的条件, 记C=gcd(L,8)9L,由于x与C不一定互质,故不满足用费马小定理使用的条件,
应 用 欧 拉 定 理 , 得 到 可 行 解 ϕ ( C ) , 满 足 : 应用欧拉定理,得到可行解\phi(C),满足: 应用欧拉定理,得到可行解ϕ(C),满足:
1 0 ϕ ( C ) ≡ 1 ( m o d C ) 10^{\phi(C)}≡1(mod\ C) 10ϕ(C)≡1(mod C)
因 为 我 们 要 求 最 小 的 正 整 数 解 , 因为我们要求最小的正整数解, 因为我们要求最小的正整数解,
可 以 证 明 : ϕ ( C ) 的 因 子 同 样 也 是 上 式 的 解 , 可以证明:\phi(C)的因子同样也是上式的解, 可以证明:ϕ(C)的因子同样也是上式的解,
故 我 们 还 需 枚 举 ϕ ( C ) 的 因 子 , 逐 个 判 断 是 否 满 足 条 件 , 输 出 最 小 的 解 。 故我们还需枚举\phi(C)的因子,逐个判断是否满足条件,输出最小的解。 故我们还需枚举ϕ(C)的因子,逐个判断是否满足条件,输出最小的解。
判断无解:
1 0 x ≡ 1 ( m o d C ) < = > 1 0 x + C y = 1 10^x≡1(mod\ C)\quad<=>\quad10^x+Cy=1 10x≡1(mod C)<=>10x+Cy=1
g c d ( 10 , C ) ≠ 1 , 则 等 式 两 边 同 除 g c d ( 10 , C ) , 发 现 等 式 右 边 不 是 整 数 , 此 时 无 解 。 gcd(10,C)≠1,则等式两边同除gcd(10,C),发现等式右边不是整数,此时无解。 gcd(10,C)=1,则等式两边同除gcd(10,C),发现等式右边不是整数,此时无解。
具体步骤:
① 、 计 算 C = 9 L g c d ( L , 8 ) , 判 断 是 否 有 解 。 ①、计算C=\frac{9L}{gcd(L,8)},判断是否有解。 ①、计算C=gcd(L,8)9L,判断是否有解。
② 、 若 有 解 , 根 据 定 义 计 算 C = P 1 a 1 P 2 a 2 . . . P k a k 的 欧 拉 函 数 : ②、若有解,根据定义计算C=P_1^{a_1}P_2^{a_2}...P_k^{a_k}的欧拉函数: ②、若有解,根据定义计算C=P1a1P2a2...Pkak的欧拉函数:
ϕ ( C ) = C ( 1 − 1 P 1 ) ( 1 − 1 P 2 ) . . . ( 1 − 1 P k ) , \phi(C)=C(1-\frac{1}{P_1})(1-\frac{1}{P_2})...(1-\frac{1}{P_k}), ϕ(C)=C(1−P11)(1−P21)...(1−Pk1),
③ 、 接 着 枚 举 ϕ ( C ) 的 所 有 因 子 i 和 ϕ ( C ) / i , 对 每 一 个 质 因 子 p , 判 断 1 0 p ≡ 1 ( m o d C ) 是 否 成 立 , ③、接着枚举\phi(C)的所有因子i和\phi(C)/i,对每一个质因子p,判断10^p≡1(mod\ C)是否成立, ③、接着枚举ϕ(C)的所有因子i和ϕ(C)/i,对每一个质因子p,判断10p≡1(mod C)是否成立,
输 出 满 足 条 件 的 最 小 的 因 子 p 。 \qquad输出满足条件的最小的因子p。 输出满足条件的最小的因子p。
注意:
本 题 虽 然 考 察 同 余 方 程 , 但 并 未 使 用 到 扩 展 欧 几 里 得 算 法 。 本题虽然考察同余方程,但并未使用到扩展欧几里得算法。 本题虽然考察同余方程,但并未使用到扩展欧几里得算法。
使 用 快 速 幂 计 算 1 0 p 对 C 取 模 时 , 注 意 乘 法 的 过 程 可 能 会 爆 l o n g l o n g , 使用快速幂计算10^p对C取模时,注意乘法的过程可能会爆long\ long, 使用快速幂计算10p对C取模时,注意乘法的过程可能会爆long long,
因 此 , 我 们 用 快 速 ( 龟 速 ) 乘 法 来 进 行 每 一 次 乘 法 操 作 。 因此,我们用快速(龟速)乘法来进行每一次乘法操作。 因此,我们用快速(龟速)乘法来进行每一次乘法操作。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll quick_mul(ll a,ll b,ll mod)
{
ll res=0;
while(b)
{
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll quick_pow(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if(b&1) res=quick_mul(res,a,mod);
a=quick_mul(a,a,mod);
b>>=1;
}
return res;
}
ll gcd(ll a,ll b)
{
return b ? gcd(b,a%b) : a;
}
ll get_euler(ll C) //定义求欧拉函数
{
ll 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;
}
int main()
{
ll L;
int T=1;
while(cin>>L,L)
{
ll C=L/gcd(L,8)*9;
ll res=1e18;
if(gcd(10,C)!=1) res=0;
else
{
ll phi_C=get_euler(C);
for(ll i=1;i<=phi_C/i;i++)
if(phi_C%i==0)
{
if(quick_pow(10,i,C)==1) res=min(res,i);
if(quick_pow(10,phi_C/i,C)==1) res=min(res,phi_C/i);
}
}
printf("Case %d: %lld\n",T++,res);
}
return 0;
}