【矩阵快速幂】[NOI2011]兔农
来源:互联网 发布:redis与数据库 编辑:程序博客网 时间:2024/06/05 22:34
题目描述
Description
农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题。问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第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的余数即可。
Input
输入一行,包含三个正整数n, k, p。
Output
输出一行,包含一个整数,表示栋栋第n个月的兔子对数除p的余数。
Sample Input
6 7 100
Sample Output
7
HINT
1<=N<=10^18
Source
Day1
分析
有一个结论,模
这个结论让我们可以暴力求一次模k意义下的循环节。
再来看题目,当第一次遇到
那我们来看看减一之后在模k意义下的这个数列。
我们先这又是一个
我们可以先预处理出乘法逆元,然后在求循环节的时候,假设在
矩阵不能像一般的
代码
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MOD p#define MAXK 1000000typedef long long LL;int k,p,a[MAXK*10+10],cir,c[MAXK+10],nxt[MAXK+10],ans,inv[MAXK+10],bgc;bool vis[MAXK+10];LL n,dep[MAXK+10];template<class T>void Read(T &x){ char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; }}void exgcd(int a,int b,int &d,int &x,int &y){ if(!b){ d=a; x=1; y=0; return; } exgcd(b,a%b,d,y,x); y-=a/b*x;}// gcd (a,b)=gcd(b,a-a/b*b)//ax+by=bx'+(a-a/b*b)y'//ax+by=bx'+ay'-a/b*by'=ay'+b(x'-a/b*y')//x=y' y=x'-a/b*y'void prepare(){ int i,d,x,y; inv[1]=1; for(i=2;i<k;i++){ exgcd(i,k,d,x,y); if(d==1) inv[i]=((x%k)+k)%k; } a[0]=a[1]=1; for(i=2;;i++){ a[i]=(a[i-1]+a[i-2])%k; if(a[i]&&inv[a[i]]&&!c[inv[a[i]]]) c[inv[a[i]]]=i+1,nxt[inv[a[i]]]=1ll*a[i-1]*inv[a[i]]%k; if(!a[i-1]&&a[i]==1) break; } cir=i;}struct Matrix{ int a[3][3]; inline Matrix(){ memset(a,0,sizeof a); } inline Matrix(int){ memset(a,0,sizeof a); a[0][0]=a[1][1]=a[2][2]=1; } inline Matrix operator * (const Matrix &b)const{ Matrix c; static int i,j,k; for(i=0;i<3;i++) for(j=0;j<3;j++) if(a[i][j]) for(k=0;k<3;k++) c.a[i][k]=(c.a[i][k]+1ll*a[i][j]*b.a[j][k])%MOD; return c; } inline Matrix& operator *=(const Matrix &b){ return *this=*this*b; }}x,y(1),z(1),xx;//f[0] f[-1] 1* aMatrix quick_pow(Matrix a,LL b){ Matrix ret(1); while(b){ if(b&1) ret*=a; a*=a; b>>=1; } return ret;}void solve(){ int b; LL tot=0; b=1; x.a[0][0]=x.a[1][0]=x.a[0][1]=x.a[2][2]=1; xx=x,xx.a[2][0]=p-1; while(!vis[b]&&nxt[b]&&tot+c[b]<=n){ vis[b]=1; dep[b]=tot; tot+=c[b]; y*=quick_pow(x,c[b]-1); y*=xx; b=nxt[b]; } if(nxt[b]&&tot+c[b]<=n){ bgc=b; do{ z*=quick_pow(x,c[b]-1); z*=xx; b=nxt[b]; }while(b!=bgc); y*=quick_pow(z,(n-tot)/(tot-dep[b])); tot+=(n-tot)/(tot-dep[b])*(tot-dep[b]); while(tot+c[b]<=n){ tot+=c[b]; y*=quick_pow(x,c[b]-1); y*=xx; b=nxt[b]; } } y*=quick_pow(x,n-tot); ans=(y.a[1][0]+y.a[2][0])%MOD;}int main(){ Read(n),Read(k),Read(p); prepare(); solve(); printf("%d\n",ans);}
- 【矩阵快速幂】[NOI2011]兔农
- bzoj2432: [Noi2011]兔农 快速幂+数论
- 【数论】【矩阵乘法】【NOI2011】兔农
- bzoj 2432 [Noi2011]兔农 [矩阵]
- 矩阵乘+坑 [NOI2011] 兔农
- bzoj 2432: [Noi2011]兔农 (数论+矩阵乘法)
- 快速矩阵快速幂
- [NOI2011]兔农(斐波那契数列+乘法逆+矩阵加速)
- 转移矩阵+矩阵快速幂
- 矩阵乘法 矩阵快速幂
- 构造矩阵+矩阵快速幂
- 矩阵快速幂,矩阵加法,矩阵乘法
- 快速幂||矩阵快速幂
- 快速幂&矩阵快速幂
- 快速幂,矩阵快速幂
- 快速幂 矩阵快速幂
- 快速幂&矩阵快速幂
- 【快速幂】【矩阵快速幂】
- C#学习笔记--引用类型分类,对象类型、字符串类型、数字类型,类型转换
- yum 常用命令介绍
- 实例简述Spring AOP之对AspectJ语法的支持
- 实例简述Spring AOP之对AspectJ语法的支持
- linux第二天
- 【矩阵快速幂】[NOI2011]兔农
- TensorFlow博客翻译——TensorFlow v0.9发布,带有增强版的移动支持
- [Android] Android开发优化之——对Bitmap的内存优化
- uC/OS-II的任务管理和调度
- EasyARM-iMX283A 安装交叉编译工具链
- SSH学习之Struts2(一)
- 第08章:java常用类库
- Eclipse和Android Studio2.0检测不到手机的解决方法
- Spring.NET学习笔记12——面向切面编程(基础篇) Level 300