1. 程式人生 > >【bzoj2432】【NOI2011】兔農

【bzoj2432】【NOI2011】兔農

color 正在 小兔 就會 amp noi return struct spa

題目描述

農夫棟棟近年收入不景氣,正在他發愁如何能多賺點錢時,他聽到隔壁的小 朋友在討論兔子繁殖的問題。 問題是這樣的:第一個月初有一對剛出生的小兔子,經過兩個月長大後,這 對兔子從第三個月開始,每個月初生一對小兔子。新出生的小兔子生長兩個月後 又能每個月生出一對小兔子。問第 n 個月有多少只兔子? 聰明的你可能已經發現,第 n 個月的兔子數正好是第 n 個 Fibonacci(斐波那 契)數。棟棟不懂什麽是 Fibonacci 數,但他也發現了規律:第 i+2 個月的兔子數 等於第 i 個月的兔子數加上第 i+1 個月的兔子數。前幾個月的兔子數依次為: 1 1 2 3 5 8 13 21 34 … 棟棟發現越到後面兔子數增長的越快,期待養兔子一定能賺大錢,於是棟棟 在第一個月初買了一對小兔子開始飼養。 每天,棟棟都要給兔子們餵食,兔子們吃食時非常特別,總是每 k 對兔子圍 成一圈,最後剩下的不足 k 對的圍成一圈,由於兔子特別害怕孤獨,從第三個月 開始,如果吃食時圍成某一個圈的只有一對兔子,這對兔子就會很快死掉。 我們假設死去的總是剛出生的兔子,那麽每個月的兔子數仍然是可以計算的。 例如,當 k=7 時,前幾個月的兔子數依次為: 1 1 2 3 5 7
12 19 31 49 80 … 給定 n,你能幫助棟棟計算第 n 個月他有多少對兔子麽?由於答案可能非常 大,你只需要告訴棟棟第 n 個月的兔子對數除 p 的余數即可。

輸入

輸入一行,包含三個正整數 n, k, p。

輸出

輸出一行,包含一個整數,表示棟棟第 n 個月的兔子對數除 p 的余數。

樣例輸入

6 7 100

樣例輸出

7

題解:

  矩陣快速冪+......萬惡的分類討論。

  %%%%http://blog.csdn.net/u011265346/article/details/46331419。

  

#include<cstdio>
#include<map>
#include
<iostream> #include<cstring> using namespace std; map<long long ,int >mp; typedef long long ll; const int N=(int ) 1e6+50; inline ll powmod(ll a,ll b,ll p){ ll ans=1; while(b){ if(b&1) ans=a*ans%p; a=a*a%p; b>>=1; }return ans; } int vis[12
*N]; ll n,k,p,phi_k; ll fib[12*N]; ll step[N]; int cnt,from; bool circle; inline ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } inline ll phi(ll x){ ll ans=1; for(ll i=2;i*i<=x;i++) if(x%i==0){ ans*=i-1; x/=i; while(x%i==0) x/=i,ans*=i; } return ans*(x==1?1:x-1); } inline void init(){ phi_k=phi(k); fib[1]=fib[2]=1; for(int i=3;i<=6*k;i++){ fib[i]=(fib[i-1]+fib[i-2])%k; if(!vis[fib[i]]) vis[fib[i]]=i; } for(ll i=1,j;;){ mp[i]=++cnt; ll t=gcd(i,k); if(t>1) break; else{ j=powmod(i,phi_k-1,k); if(!vis[j]){ break; } else{ i=i*fib[vis[j]-1]%k; step[cnt]=(ll)vis[j]; if(mp.count(i)){ circle=true; from=mp[i];break; } } } } step[1]-=2; } struct Matrix{ ll a[4][4]; Matrix(){memset(a,0,sizeof(a));} void e(){ a[1][2]=a[2][1]=a[2][2]=a[3][3]=1; } void f(){ a[1][1]=a[2][2]=a[3][3]=1;a[3][2]=-1; } friend Matrix operator *(Matrix x,Matrix y){ Matrix c; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++){ for(int k=1;k<=3;k++) (c.a[i][j]+=x.a[i][k]*y.a[k][j])%=p; (c.a[i][j]+=p)%=p; } return c; } friend Matrix operator ^(Matrix x,ll b){ Matrix ans; for(int i=1;i<=3;i++) ans.a[i][i]=1; while(b){ if(b&1) ans=ans*x; b>>=1; x=x*x; }return ans; } void print(){ for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++)printf("%lld ",a[i][j]);puts(""); } } }a,b; ll ans; inline void solve(){ if(circle){ n-=2; a.e(),b.f(); Matrix now; now.a[1][1]=now.a[1][2]=now.a[1][3]=1; int i; for(i=1;i<from&&n>=step[i];n-=step[i],i++) now=now*(a^step[i])*b; if(i<from) { now=now*(a^n); ans=now.a[1][2]; return ; } else{ ll all_cic=0; for(i=from;i<=cnt;i++) all_cic+=step[i]; ll cic=n/all_cic; n-=cic*all_cic; Matrix c; for(i=1;i<=3;i++) c.a[i][i]=1; for(i=from;i<=cnt;i++) c=c*(a^step[i])*b; now=now*(c^cic); for(i=from;n>=step[i];n-=step[i],i++) now=now*(a^step[i])*b; now=now*(a^n); ans=now.a[1][2];return; } } else{ n-=2; a.e(),b.f(); Matrix now; now.a[1][1]=now.a[1][2]=now.a[1][3]=1; int i; for(i=1;step[i]&&n>=step[i];n-=step[i],i++){ now=now*(a^step[i])*b; } now=now*(a^n);ans=now.a[1][2];return ; } } int main(){ scanf("%lld%lld%lld",&n,&k,&p); if(n==1){ printf("%lld\n",1%p); return 0; } init(); solve(); printf("%lld\n",ans); }

【bzoj2432】【NOI2011】兔農