poj 3696 The Luckiest Number
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 9\cdot n|(10^x-1)\cdot 8$
$\Rightarrow \frac{9\cdot n}{gcd(n,8)}|\frac{(10^x-1)\cdot8}{gcd(n,8)}$
$\because gcd(\frac n{gcd(n,8)},\frac8{gcd(n,8)})=1$
且$gcd(9,8)=1$
$\therefore gcd(\frac{9\cdot n}{gcd(n,8)},\frac{8}{gcd(n,8)})=1$
$\Rightarrow \frac{9\cdot n}{gcd(n,8)}|10^x-1$
$\Rightarrow 10^x\equiv1(mod\frac{9\cdot 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\n"); 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\n",minn); } }
小結:錯誤,枚舉一個數的因子其實是可以根號時間內完成的...我傻逼了......
還有,別忘記phi開始的初值是n,不是1.
poj 3696 The Luckiest Number