题目链接:http://poj.org/problem?id=3696
题目要求求最短的由连续的8构成的数使得这个数是L的倍数,我们首先求出phi(mod)可以证明a^x%mod=1的解x最大是phi(mod)而且其他解都是phi(mod)的约数,phi(mod)的约数大约是log(phi(mod))个。首先通过O(sqrt(mod))时间复杂度将mod分解质因数并计算phi(mod),他的约数个数最多是sqrt(phi(mod)),通过枚举即可。
注意需要通过ll求指数进行验证,所以需要通过加强的ll乘法对快速幂中的乘法进行优化。不然会WA,加强后的快速幂大约时间复杂度是O(logn^2)
证明:
代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const ll inf=1e18; ll L; ll phi(ll mod){ ll ans=mod; for(ll i=2;i*i<=mod;i++){ if(mod%i)continue; ans=ans/i*(i-1); while(!(mod%i))mod/=i; } if(mod>1)ans=ans/mod*(mod-1); return ans; } ll ksc(ll n,ll k,ll mod){//n*k mod mod ll ans=0; while(k){ if(k&1)ans=(ans+n)%mod; k>>=1; n=(n*2)%mod; } return ans; } ll pow(ll n,ll k,ll mod){ ll ans=1; n%=mod; while(k){ if(k&1)ans=ksc(ans,n,mod);//ll防止溢出 n=ksc(n,n,mod); k>>=1; } return ans; } ll gcd(ll x,ll y){ return y?gcd(y,x%y):x; } int main(){ int T=0; while(scanf("%lld",&L) && L){ ll mod= L/gcd(L,8ll)*9ll; ll xmax=phi(mod); ll ans=inf; for(ll i=1;i*i<=xmax;i++){//枚举phi(mod)的所有的约数,除了开根的都是成对出现的 if(xmax%i)continue; if(pow(10,i,mod)==1)ans=min(ans,i); if(i!=xmax/i && pow(10,xmax/i,mod)==1)ans=min(ans,xmax/i); } printf("Case %d: ",++T); if(ans==inf)printf("0 "); else printf("%lld ",ans); } return 0; }