题目大意:
给出多个询问,
每个询问给出一个正整数L,
问至少多少个8连在一起组成的正整数是L的倍数?
1≤L≤2∗109 1 ≤ L ≤ 2 ∗ 10 9
分析:
x个8连在一起,显然可以写成:
8(10x−1)9
8
(
10
x
−
1
)
9
我们现在是要求一个最小的x,
满足
L
L
8(10x−1)9
8
(
10
x
−
1
)
9
则可以进行一系列的转换,
L
L
8(10x−1)9
8
(
10
x
−
1
)
9
⇔
⇔
9L
9
L
|
|
9L
9
L
|
|
⇔
⇔
9L8
9
L
8
|
|
显然
9L8
9
L
8
并不一定是整数
所以我们设
d
d
为
则显然可以转化成:
9Ld
9
L
d
|
|
即
10x=1
10
x
=
1
(mod
(
m
o
d
9Ld)
9
L
d
)
引理:
当
gcd(a,n)=1
g
c
d
(
a
,
n
)
=
1
,即a,n互质的时候,满足
ax=1
a
x
=
1
(mod
(
m
o
d
n)
n
)
的最小的
x
x
为的约数
所以我们可以求出
φ(9Ld)
φ
(
9
L
d
)
然后枚举约数用快速幂判断
因为数比较大,快速幂的时候要处理一下相乘。。
我就这里炸了好久..
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b){
return b ? gcd(b, a % b) : a;
}
LL enlur(LL eup){
LL phi = eup;
for (LL i = 2; i * i <= eup; i++)
if (eup % i == 0){
phi -= phi / i;
while (eup % i == 0) eup /= i;
}
if (eup > 1) phi -= phi / eup;
return phi;
}
LL mul(LL a, LL b, LL modn){
LL num = 0;
for (; b ; b >>= 1){
if (b & 1) num = (num + a) % modn;
a = a * 2 % modn;
}
return num;
}
LL ksm(LL a, LL b, LL modn){
LL num = 1;
for (; b ; b >>= 1){
if (b & 1) num = mul(num, a, modn);
a = mul(a, a, modn);
}
return num;
}
int main(){
int cnt = 0;
LL L;
while (~scanf("%I64d", &L)){
if (!L) break;
printf("Case %d: ", ++cnt);
LL cp = gcd(L, 8);
LL rp = 9 * L / cp;
LL op = gcd(rp, 10);
if (op == 1){
LL num = enlur(rp);
LL ans1 = 0, ans2 = 0;
for (LL i = 1; i * i <= num; i++)
if (num % i == 0){
if (ksm(10, i, rp) == 1){
ans1 = i;
break;
}
if (i != num / i)
if (ksm(10, num / i, rp) == 1) ans2 = num / i;
}
if (!ans1) printf("%I64d\n", ans2);
else printf("%I64d\n", ans1);
} else printf("0\n");
}
return 0;
}