题目链接:http://poj.org/problem?id=3696
题意:给一个数N(1<=N<=2000000000);问是否存在N的倍数M,且M的各个位全部由8组成,如果存在多个取最小的M
并输出M由几个8组成。
解题思路:因为M全部由8组成,即M=(10^x -1)*8/9=k*N;
则 (10^x-1)*8/gcd(8,N)=9*k*N/gcd(8,N);
令p=8/gcd(8,N); q=9*N/gcd(8,N); 即 (10^x-1)*p=k*q;
由于p和q互质,则(10^x-1)%q==0;
根据同余定理可知,10^x ≡1(mod q)
根据欧拉定理可知当gcd(a,b)==1时,a^φ(b)≡1(mod b);
即可得出:当gcd(10,q)==1时 10^φ(q)≡1(mod q) 即通过枚举φ(q)的因子(最小因子)就能得出结果
由于N比较大,因此采用long long 型。同时做一个素数表。
在进行幂求模运算的时候可以采用快速幂的方法。
由于在进行快速幂求模的时候数据会超出long long 的表示范围,因此要进行优化。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
const int M=50000;
int p[M],v[M]; //v[M]用于保存M以内的所有素数
vector<int> T;
long long gcd(long long a,long long b) //求最大公约数
{
long long x,y,z;
if(a>b){x=a;y=b;}
else {x=b;y=a;}
while(y)
{
z=x%y;x=y;y=z;
}
return x;
}
void prime() //求出M以内的所有素数
{
memset(p,0,sizeof(p));int k=0;
for(int i=2;i<M;i++)
{
if(!p[i])
{
v[k++]=i;
for(int j=i+i;j<M;j+=i)p[j]=1;
}
}
}
long long phi(long long m) //求m的欧拉值
{
long long count=m;
for(int i=0;v[i]*v[i]<=m;i++)
{
if(m%v[i]==0)
{
count=count/v[i]*(v[i]-1);
while(m%v[i]==0)m/=v[i];
}
}
if(m>1)count=count/m*(m-1);
return count;
}
long long fun(long long a,long long b,long long c) //求a*b(mod c);
{
a%=c;
long long s=0;
while(b)
{
if(b&1)
{
s=s+a;
if(s>=c)
s=s-c;
}
a=a<<1;
if(a>=c)a=a-c;
b=b>>1;
}
return s;
}
long long power_mod(long long a,long long b,long long c) //快速幂求a的b次方对c取余
{
long long s=1;a=a%c;
while(b>=1)
{
if(b&1)s=fun(s,a,c);
a=fun(a,a,c);
b=b>>1;
}
return s;
}
void fs(long long m)
{
T.clear();
for(int i=0;v[i]*v[i]<=m;i++)
{
while(m%v[i]==0){T.push_back(v[i]);m/=v[i];}
}
if(m>1)T.push_back(m);
}
int main()
{
long long m;int k=0;prime();
while(scanf("%lld",&m)&&m)
{
k++;printf("Case %d: ",k);
m=9*m/gcd(8,m);
if(gcd(m,10)!=1)printf("0\n");
else
{
long long n=phi(m);long long mi=n;bool flat=true;
while(flat)
{
fs(n);
flat=false;
for(int i=0;i<T.size();i++)
{
if(power_mod(10,n/T[i],m)==1)
{flat=true;if(n/T[i]<mi)mi=(n/T[i]);}
}
n=mi;
}
printf("%lld\n",mi);
}
}
}