[题解](同余)POJ_3696_The Luckiest Number
还是挺难的吧......勉强看懂调了半天
首先表达式可以写成 8(10^x -1)/9,题意为求一个最小的x使L | 8(10^x -1)/9
设d=gcd(L,8)
L | 8(10^x -1)/9
<=>9L | 8(10^x -1)
<=>9L/d | 10^x -1 (因为 9L/d 和 8/d 互质了 所以 9L/d 能整除(8/d)*(10^x-1)和 8/d 无关,所以可以去掉)
<=>10^x 同余 1(mod 9L/d)
引理:
若a,n互质,则满足10^x同余1(mod n)的最小正整数x0是phi(n)的约数
反证法:
假设满足a^x 同余 1(mod n)的最小正整数x0不能整除phi(n)
设phi(n)=q*x0+r(0<r<x0),因为a^x0 同余1(mod n),所以a^(q*x0)同余1(mod n)
根据欧拉定理a^phi(n)同余1(mod n),所以a^r同余1(mod n),与x0最小矛盾
无解的时候就是q与10不互质的时候,因为若q与10有公因子d:
1.若d=2,q=2*k,那么10^x=2^x*5^x=1%2k
即2^x*5^x=1+2k*m,左边为偶数,右边为奇数,显然矛盾。
2.若d=5,q=5*k,那么10^x=2^x*5^x=1%5k
即2^x*5^x=1+5k*m,左边是5的倍数,右边不是5的倍数,显然矛盾。
注意:乘的时候会爆longlong,手写乘法,要用根号的试除法求约数,不然会T
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; ll n,cnt; ll x[100000]; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll eular(ll n){ ll ans=n; for(ll i=2;i*i<=n;i++){ if(n%i==0){ ans=ans/i*(i-1); while(n%i==0)n/=i; } } if(n>1)ans=ans/n*(n-1); return ans; } ll mul(ll a,ll b,ll mod){ ll ans=0; while(b){ if(b&1)ans=(ans+a)%mod; a=(a<<1)%mod; b>>=1; } return ans; } ll qpow(ll a,ll b,ll mod){ ll base=a,ans=1; while(b){ if(b&1)ans=mul(ans,base,mod); base=mul(base,base,mod); b>>=1; } return ans%mod; } int main(){ int t=0; while(1){ int fl=0;cnt=0; scanf("%lld",&n); if(n==0)break; ll d=9*n/gcd(n,8); if(gcd(10,d)!=1){ printf("Case %d: 0\n",++t); } else{ ll phi=eular(d); for(ll i=1;i*i<=phi;i++){ if(phi%i==0){ x[++cnt]=i; if(i*i!=phi)x[++cnt]=phi/i; } } sort(x+1,x+cnt+1); for(int i=1;i<=cnt;i++) if(qpow(10,x[i],d)==1){ printf("Case %d: %lld\n",++t,x[i]); break; } } } }