题目描述
至少多少个 8 8 连在一起组成的数是 的倍数。
算法分析
设 x x 个 连在一起组成的数是 l l 的倍数,则表示为 。
转化一下就是 9×l|8×(10x−1) 9 × l | 8 × ( 10 x − 1 ) ,接下来怎么转化?
9×l 9 × l 是 10x−1 10 x − 1 的约数吗?不一定,还需要从重去除 l l 与 分解质因数后的公共部分,即 gcd(8,l) g c d ( 8 , l ) 。
所以上式就变成 9×lgcd(8,l)|10x−1 9 × l g c d ( 8 , l ) | 10 x − 1 ,即 10x≡1(mod9×lgcd(8,l)) 10 x ≡ 1 ( mod 9 × l g c d ( 8 , l ) ) 。
有一个结论:
- 10x≡1(modp) 10 x ≡ 1 ( mod p ) ,满足条件的最小的 x x 一定是 的约数。(反证法)
然后就可以求出 ϕ(9×lgcd(8,l)) ϕ ( 9 × l g c d ( 8 , l ) ) 的值,枚举它的所有约数,使用快速幂一一判断是否满足条件即可。
注意开 64 64 位整数,计算快速幂的时候中间结果会超过 64 64 位整数范围,因此需要利用之前本博客中介绍的技巧计算。
代码实现
#include <cstdio>
#include <climits>
#include <algorithm>
typedef long long int ll;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
inline ll eular(ll n) {
ll ans=n;
for(ll i=2;i*i<=n;++i) {
if(n%i==0) {
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
ll p;
ll mul(ll a,ll b) {
ll temp=(long double)a*b/p;
ll ans=a*b-temp*p;
if(ans>=p) ans-=p;
if(ans<0) ans+=p;
return ans;
}
ll pow(ll n,ll k) {
ll ans=1;
while(k) {
if(k&1) ans=mul(ans,n);
n=mul(n,n);k>>=1;
}
return ans;
}
int main() {
ll l;int kase=0;
while(scanf("%lld",&l)==1&&l) {
p=l*9/gcd(8,l);ll n=eular(p),ans=1LL<<60;
for(ll i=1;i*i<=n;++i) {
if(n%i==0) {
if(pow(10,i)==1) {ans=i;break;}
else if(i*i!=n&&pow(10,n/i)==1) ans=std::min(ans,n/i);
}
}
printf("Case %d: %lld\n",++kase,ans==1LL<<60?0:ans);
}
return 0;
}