您的位置:首页 > 其它

【bzoj2432】【NOI2011】兔农

2017-08-04 18:02 197 查看

题目描述

农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小 朋友在讨论兔子繁殖的问题。 问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这 对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后 又能每个月生出一对小兔子。问第 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
;
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: