The Luckiest Number
题目大意:给你一个int范围内的正整数n,求这样的最小的x,使得:连续的x个8可以被n整除。
注释:如果无解输出0。poj多组数据,第i组数据前面加上Case i: 即可。
想法:这题还是挺好的。我最开始的想法是一定有超级多的数输出0。然后...我就在哪里找啊找....其实这道题是一道比较好玩儿的数论题。我们思考:连续的8可用什么来表示出来?$frac{(10^x-1)}{9}cdot 8$。其实想到这一步这题就做完了。这题的精髓就在于告诉我们连续的连续的一串数的表达方式。想到这点其实有一个比较容易接受的方法:这鬼东西是一个等比数列。然后,式子就可以化成了以下的形式及推导
$Rightarrow n|frac{10^x-1}{9}cdot 8$
$Rightarrow 9cdot n|(10^x-1)cdot 8$
$Rightarrow frac{9cdot n}{gcd(n,8)}|frac{(10^x-1)cdot8}{gcd(n,8)}$
$ecause gcd(frac n{gcd(n,8)},frac8{gcd(n,8)})=1$
且$gcd(9,8)=1$
$ herefore gcd(frac{9cdot n}{gcd(n,8)},frac{8}{gcd(n,8)})=1$
$Rightarrow frac{9cdot n}{gcd(n,8)}|10^x-1$
$Rightarrow 10^xequiv1(modfrac{9cdot n}{gcd(n,8)})$
所以此时,我们只需要枚举mod数即可。但是有些操作是不必要的,在此,我们有两种简单的优化:
1.对于mod数取$varphi$,然后暴力枚举$varphi$的所有因子。时间复杂度$O(sqrt{n})$,验证是用快速幂,时间复杂度O(logn),所以,总时间复杂$O(sqrt{n}cdot {logn})$。
2.用BSGS优化,我没想到(鸣谢CQzhangyu)。时间复杂度同理。
但是对于第一种我们可以用Miller_Rabin 和Pullard_rho进行爆炸般的优化,但是没什么必要......
最后,附上丑陋的代码......
#include <iostream> #include <cstdio> typedef long long ll; using namespace std; ll gcd(ll a,ll b)//只取一次mod的gcd,鸣谢EdwardFrog { return b?gcd(b,a%b):a; } ll quick_multiply(ll a,ll b,ll mod)//快速乘,防止爆longlong,虽然没有必要 { ll ans=0; a%=mod; b%=mod; while(b) { if(b&1) ans=(ans+a)%mod; b>>=1; a=(a+a)%mod; } return ans; } ll quick_power(ll a,ll b,ll mod)//这题不爆longlong,但是这样是必须的,因为9*n在longlong范围内 { ll ans=1; a%=mod; while(b) { if(b&1) ans=quick_multiply(ans,a,mod); b>>=1; a=quick_multiply(a,a,mod); } return ans; } int main() { ll n; ll cnt=0; while(1) { scanf("%lld",&n); if(n==0) return 0; printf("Case %lld: ",++cnt); n=9*n/gcd(n,8); ll m=n; ll phi=n; if(gcd(n,10)!=1)//这是欧拉定理所必须满足的,如果不行显然无解 { printf("0 "); continue; } for(ll i=2;i*i<=m;++i) { if(m%i==0) { phi=phi/i*(i-1); while(m%i==0) { m/=i; } } } if(m!=1) phi=phi/m*(m-1); // cout<<"phi="<<phi<<endl;调试信息 ll minn=phi;//我想取最小值,且最大值是phi for(ll i=1;i*i<=phi;i++)//这步是验证。 { if(phi%i==0) { if(quick_power(10,i,n)==1) minn=min(minn,i); if(quick_power(10,phi/i,n)==1) minn=min(minn,phi/i); } } printf("%lld ",minn); } }
小结:错误,枚举一个数的因子其实是可以根号时间内完成的...我傻逼了......
还有,别忘记phi开始的初值是n,不是1.