题目链接:https://vjudge.net/problem/POJ-3696
题目大意:给定一个数L,问是否存在这样的kL=88...888,求最小的全是8的数的长度,如果无法构造,输出0
题解思路:
全是8的数可以表示为


而


gcd变形可得:



等式为:

要让等式成立则必有:

可得:

移项得:

由欧拉定理可知:

如果


如果互质的话,那么10的指数在 mod q 的条件下的循环节的上限就是

在实现上需要注意的是这里的q会非常大,相对的其欧拉函数也会比较大,需在mod q意义下快速幂计算10^k,并且这里为了防止爆longlong,要手写快速乘。
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
#define ll long long
ll Phi(ll x)
{
ll ans=x;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
ans=ans/i*(i-1);
while(x%i==0)
{
x/=i;
}
}
}
if(x>1)
{
ans=ans/x*(x-1);
}
return ans;
}
ll mul(ll a,ll b,ll c)
{
ll res=0;
while(b)
{
if(b & 1)
{
res=(res+a)%c;
}
a=(a+a)%c;
b=b>>1;
}
return res;
}
ll quick_pow_mod(ll a,ll b,ll c)
{
ll res=1;
while(b)
{
if(b & 1)
{
res=mul(res,a,c)%c;
}
a=mul(a,a,c)%c;
b=b>>1;
}
return res;
}
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
vector<ll>fac;
void get_factor(ll n)
{
ll num=n;
for(ll i=2;i*i<=num;i++)
{
if(n%i==0)
{
fac.push_back(i);
while(n%i==0)
{
n/=i;
}
}
}
if(n>1)fac.push_back(n);
}
int main()
{
ll n;
for(int kase=1;;kase++)
{
fac.clear();
scanf("%lld",&n);if(n==0)break;
cout<<"Case "<<kase<<": ";
ll q=n/gcd(n,8)*9;
if(gcd(10,q)!=1)
{
cout<<0<<endl;
continue;
}
ll phi=Phi(q);
//cout<<"phi:"<<phi<<endl;
get_factor(phi);
sort(fac.begin(),fac.end());
for(int i=0;i<fac.size();i++)
{
while(1)
{
phi/=fac[i];
if(quick_pow_mod(10,phi,q)!=1)
{
phi*=fac[i];
break;
}
else if(phi%fac[i])
{
break;
}
}
}
cout<<phi<<endl;
}
return 0;
}
来源:CSDN
作者:neuq_zsmj
链接:https://blog.csdn.net/neuq_zsmj/article/details/84308384