题目描述
题目大意:给你一个数L(1≤L≤2,000,000,000),求一个最小的全部由8组成的是L倍数的十进制数,输出它的位数,如果无解输出0。
题解
这是一道如果我不看题解就永远也想不到的题。
一个全部由8组成的数可以这样表示
89(10x−1)
其中 x 为正整数
然后我们要求的就是一个这样的
即
8(10x−1)=9kL
令 d=(8,9L)=(8,L),p=8d,q=9Ld ,有
p(10x−1)=kq
此时
p
和
10x≡1(mod q)
这个东西像什么?欧拉定理!当 (10,q)=1 时 x=φ(q) 就是一组解。
不一定是最小的解怎么办?枚举
φ(q)
的约数看看是否可行。如果
10min=1
,而
10φ(q)=1
,必有
min|φ(q)
,相当于所有周期都是最小周期的倍数。
注意要找约数而不是质因数,没有为什么。
注意这里两个long long相乘会爆,用快速乘就行了(就是将一个数分解成二进制按位累加而已)。
当 10 与 q <script type="math/tex" id="MathJax-Element-20">q</script>不互质时显然无解。
时间复杂度:O(跑得过)。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long LL;
int Case;
LL L, Phi, d, q, ans;
LL Gcd(LL x, LL y){
if(!y) return x;
return Gcd(y, x % y);
}
LL Calc(LL x){
LL res = x;
for(LL i = 2; i * i <= x; i++)
if(x % i == 0){
res /= i;
res *= i - 1LL;
while(x % i == 0) x /= i;
}
if(x != 1){
res /= x;
res *= x - 1LL;
}
return res;
}
LL Muti(LL x, LL y, LL MOD){
LL res = 0LL;
while(y){
if(y & 1) res = (res + x) % MOD;
x = (x << 1) % MOD;
y >>= 1LL;
}
return res;
}
LL Pow(LL x, LL y, LL MOD){
LL res = 1LL;
while(y){
if(y & 1) res = Muti(res, x, MOD);
x = Muti(x, x, MOD);
y >>= 1LL;
}
return res;
}
int main(){
while(~ scanf("%I64d", &L) && L){
d = Gcd(8LL, L);
q = 9 * L / d;
if(q % 2 == 0 || q % 5 == 0) ans = 0LL;
else{
ans = Phi = Calc(q);
for(LL i = 1; i * i <= Phi; i++){
if(Phi % i == 0){
if(Pow(10LL, i, q) == 1LL) ans = min(ans, i);
if(i != Phi/i && Pow(10LL, Phi/i, q) == 1LL) ans = min(ans, Phi/i);
}
}
}
printf("Case %d: %I64d\n", ++Case, ans);
}
return 0;
}