poj3358 Period of an Infinite Binary Expansion
阿新 • • 發佈:2018-01-03
href sum using clas 我們 dot 現在 www. blog
Period of an Infinite Binary Expansion
題目大意:給你一個分數,求這個分數二進制表示下從第幾位開始循環,並求出最小循環節長度。
註釋:int範圍內。
想法:這題說實話,是一道神題!我們思考一下,如何將一個小數換成二進制?連續的乘2,然後取首位。這樣的比較簡潔的轉換方式註定了這題其實是可做的。我們可以抓住循環節的在這樣的方法下是怎樣形成的?顯然,存在一個x,使得每多乘$2^x$都會使得所形成的答案相同。第二點,我們知道,一個分數的循環節開始之前是不參與循環的。這樣,我們思考,多次反復的乘以2,它的整數部分modb是相同的對吧!?!我們在此就有一個式子,就是說
$2^i\cdot a\equiv 2^j\cdot a(mod\ b)$。其中j>i
可以變形為$2^j\cdot a-2^i\cdot a\equiv 0(mod\ b)$
$\Rightarrow 2^i\cdot a\cdot(2^{j-i}-1)$首先,我們在此之前不妨現將a,b弄成互質。現在,gcd(a,b)=1,所以,我們有
$2^i\cdot (2^{j-i}-1)\equiv 0(mod\ b)$
顯然,我們想求最小值,我們發現,如果i的值增加,循環節的長度是不會改變的,所以,我們必須求出最小的且滿足題意的i,而這個i,就是b中2的個數。剩下的,就是另一道題了。參考博主博客The Luckiest Number(The Luckiest Number?猛戳)。
最後,附上醜陋的代碼......
1 #include <iostream> 2 #include <cstdio> 3 typedef long long ll; 4 using namespace std; 5 ll gcd(ll a,ll b) 6 { 7 return b?gcd(b,a%b):a; 8 } 9 ll quick_multiply(ll a,ll b,ll mod) 10 { 11 ll ans=0; 12 a%=mod; 13 b%=mod; 14 while(b) 15 { 16 if(b&1) ans=(ans+a)%mod; 17 b>>=1; 18 a=(a+a)%mod; 19 } 20 return ans; 21 } 22 ll quick_power(ll a,ll b,ll mod) 23 { 24 ll ans=1; 25 a%=mod; 26 while(b) 27 { 28 if(b&1) ans=quick_multiply(ans,a,mod); 29 b>>=1; 30 a=quick_multiply(a,a,mod); 31 } 32 return ans; 33 } 34 int main() 35 { 36 ll a,b; 37 ll cnt=0; 38 while(~scanf("%I64d/%I64d",&a,&b)) 39 { 40 ll k=a,r=b; 41 a/=gcd(k,r); 42 b/=gcd(k,r); 43 ll sum=0; 44 while(b%2==0) b/=2,sum++; 45 printf("Case #%I64d: %I64d,",++cnt,sum+1); 46 ll phi=b; 47 ll m=b; 48 for(int i=2;i*i<=m;++i) 49 { 50 if(m%i==0) 51 { 52 phi=phi/i*(i-1); 53 while(m%i==0) 54 { 55 m/=i; 56 } 57 } 58 } 59 if(m!=1) phi=phi/m*(m-1); 60 ll minn=phi; 61 for(ll i=1;i*i<=phi;++i) 62 { 63 if(phi%i==0) 64 { 65 if(quick_power(2,i,b)==1) minn=min(minn,i); 66 if(quick_power(2,phi/i,b)==1) minn=min(minn,phi/i); 67 } 68 } 69 printf("%I64d\n",minn); 70 } 71 }
小結,我們發現,這題對於a的取值並沒有什麽要求,證明是顯然的。
poj3358 Period of an Infinite Binary Expansion