题目:大致意思就是给你一个L,1<=L<=2,000,000,000,让你找出一个最小的数字,该数字是L的倍数,并且只由数字8组成,输出该数字的位数。
分析:这个数字可以表示成8 * (10 ^ x - 1)/9,目的就是求出最小的x,满足L | 8 * (10 ^ x - 1)/9,' | '表示整除。
设d = gcd(8 , L),下面是我的理解:
在L | 8 * (10 ^ x - 1)/9两边同时除d,就会得到L / d | 8 / d * (10 ^ x - 1)/9,令a=L / d,b=8 / d,原式就变成a | b * (10 ^ x - 1)/9,a和b必然是互质的,所以右边整除左边与b没有关系,b可以去掉。那么,L / d | 8 / d * (10 ^ x - 1)/9 ⇔ L / d | (10 ^ x - 1)/9
⇔ 9L / d | 10 ^ x - 1 ⇔ 10 ^ x ≡ 1( mod 9L / d )。
有一个结论:
若正整数 a , n 互质,则满足 a ^ x ≡ 1 (mod n) 的最小正整数 x0 是 φ(n) 的约数。
那我们只需要求出φ(9L / d)的所有因子,找到最小的满足条件的就可以了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,m,ans[100010];//ans存m的因子
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll euler(ll num)//欧拉函数
{
ll ans=num;
for(int i=2;i<=sqrt(num);i++)
{
if(num%i==0)
{
ans=ans/i*(i-1);
while(num%i==0)
num/=i;
}
}
if(num>1) ans=ans/num*(num-1);
return ans;
}
ll ksc(ll a,ll b,ll mod)//快速乘
{
ll ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
b>>=1;
a=(a+a)%mod;
}
return ans;
}
ll check(ll a,ll b,ll mod)//快速幂,检查是否满足条件
{
ll ans=1;
while(b)
{
if(b&1)
ans=ksc(ans,a,mod);
b>>=1;
a=ksc(a,a,mod);
}
return ans;
}
int main()
{
int cas=1;
while(~scanf("%lld",&n),n)
{
int cnt=0,flag=0;
ll d=gcd(8,n);
m=euler(9*n/d);//phi[9*n/d]
for(int i=1;i<=sqrt(m);i++)//找出m的所有因子
{
if(m%i==0)
{
ans[++cnt]=i;
ans[++cnt]=m/i;
}
}
sort(ans+1,ans+cnt+1);//排序,从小的开始找
for(int i=1;i<=cnt;i++)
{
if(check(10,ans[i],9*n/d)==1)
{
flag=1;
printf("Case %d: %lld\n",cas++,ans[i]);
break;
}
}
if(!flag) printf("Case %d: 0\n",cas++);
}
return 0;
}