HDU 3977 求斐波那契循環節
題意:求斐波那契數列模一個數的循環節的長度。
分析過程:首先我們知道fib數列模p如果出現了連續的1,0就意味這著開始循環了,因為接下來的項就是1 1 2 3 5等等。
那麼很顯然如果在第k位第一次出現了1,0,那麼對於以後的1,0都可以表示為k*m。
那麼,現在我們考慮如果fib數列模p在第pos位第一次出現了0,那麼設0前麵的那個數為a,則接下來的序列將是a,0,a,
a,2a,3a,5a,8a,....。可以看出a的係數就是一個fib數列,那麼我們就可以得到fib(k+i)%p=a*fib(i)%p,其中i滿
足0<i<k,所以進一步可以得到fib(i)=[a^j*fib(i-k*j)]%p。
那麼我們現在先來說說如何求fib數模一個正整數n的循環節長度:
對於這個問題,我們先對n進行素因子分解,得到:,然後先對每一個形如p^k的數計算循環節,然後它們
的最小公倍數就是n的循環節長度(當然這裏麵涉及到CRT等等方麵的基礎)。那麼現在問題就是計算p^k的循環節,這個問題
可以進一步簡化成求G(p)*p^(k-1)。其中G(p)表示fib數列模素數p的循環節長度,所以現在的問題是如何求fib數列模一個
小於10^6的素數p的循環節長度。
求fib數列模p(p是素數)的最小循環節方法:
暴力枚舉fib[i]%p==0的最小的i,然後記錄pos=i+1,設a為fib[i]%p==0的前一位數,即a=fib[i-1]
那麼我們知道fib數列模p的最小循環節長度一定是pos*x,那麼也就是說現在要求一個最小的數x,滿足,
求出x後,那麼問題就解決了,剩下的就是合並等等。
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 1000005 bool isprime[maxn]; typedef long long ll; ll prime[maxn],nprime; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } void getprime() { ll i,j; memset(isprime,1,sizeof(isprime)); nprime=0; for(i=2; i<maxn; i++) if(isprime[i]) { prime[nprime++]=i; for(j=i*i; j<maxn; j+=i) isprime[j]=0; } } ll factor[100][2],tol; void findfac(ll n) { ll x=n,l=(ll)sqrt((double)n); tol=0,memset(factor,0,sizeof(factor)); for(int i=0; prime[i]<=l; i++) if(x%prime[i]==0) { factor[tol][0]=prime[i]; while(x%prime[i]==0) factor[tol][1]++,x/=prime[i]; tol++; } if(x>1) factor[tol][0]=x,factor[tol++][1]++; } ll exp_mod(ll a,ll b,ll c) { ll ret=1; while(b) { if(b&1) ret=ret*a%c; b>>=1,a=a*a%c; } return ret; } ll getPrimeLoop(ll p)//求一個素數的循環節 { ll pos=3,f1=1,f2=1,f3=2%p,k=1e9,l=(ll)sqrt((double)p-1); while(f3) f1=f2,f2=f3,f3=(f1+f2)%p,pos++;//找到第一個值是0的點 for(ll i=1; i<=l; i++) if((p-1)%i==0) { if(exp_mod(f2,(p-1)/i,p)==1) k=min(k,(p-1)/i); if(exp_mod(f2,i,p)==1) k=min(k,i); } return pos*k; } ll solve(ll p,ll k)//求一個素數的k次方的循環節 { ll ans=getPrimeLoop(p); for(int i=0; i<k-1; i++) ans*=p; return ans; } int main() { int t,ca=0; ll n,ans; getprime(); scanf("%d",&t); while(t--) { scanf("%I64d",&n); findfac(n); ans=1; ll temp; for(int i=0; i<tol; i++) temp=solve(factor[i][0],factor[i][1]),ans=ans/gcd(ans,temp)*temp; printf("Case #%d: %I64d\n",++ca,ans); } return 0; }
最後更新:2017-04-03 16:49:04
上一篇:
C# VS2012操作word文檔 (一).創建文檔
下一篇:
C# 連接SQLServer數據庫及登錄驗證知識
流著碼農的血,為突破理論極限值而生 | 阿裏中間件性能挑戰賽內部賽全記錄
關於幾個網絡編程的java開源框架
“痛點”商機來臨,“痛客計劃”能否引領創業變革?
[算法] 定義一個函數,刪除字符串中所有重複出現的字符。
傳未來iPad將物體“拉出”屏幕
VC++技術內幕(第四版)筆記--SetWindowExt和SetViewportExt
Fastjson 在HiTSDB中的應用
Cortex係列ARM內核介紹
Memory network (MemNN) & End to End memory network (MemN2N) & Dynamic memory network
GridView控件 System.NullReferenceException