#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,p;
ll m;
struct node{
//save
ll g[4][4];
}f,res;
void ORI(node &x){ //单位矩阵
for(int i = 1;i <= 2;i++){
for(int j = 1;j <= 2;j++){
if(i==j) x.g[i][j] = 1LL;
else x.g[i][j] = 0LL;
}
}
}
void sq_t(node &x,node &y,node &z){
memset(z.g,0,sizeof(z.g));//预设结果矩阵为空
int i,j,k;
for(i = 1;i <= 2;i++){
for(k = 1;k <= 2;k++){
for(j = 1;j <= 2;j++){
z.g[i][k] += x.g[i][j] * y.g[j][k]; //计算
if(z.g[i][k] >= m) {z.g[i][k] %= m;} //驱魔
}
}
}
}
void outp(node &x){
for(int i = 1;i <= 2;i++){
for(int k = 1;k <= 2;k++){
cout<<x.g[i][k]<<' ';
}
printf("\n");
}
printf("END\n\n");
}
void ksm(int yy){
ORI(res);//预设结果为单位矩阵(y = 1)
node temp,t;
temp = f;//预设操作矩阵为f矩阵
while(yy){
if(yy&1) {
sq_t(res,temp,t);res = t;//y = y*x
}
sq_t(temp,temp,t);temp = t;//x = x*x
yy>>=1;
}
}
ll solve(){ //即原递推函数,需要考虑特判_公式_取模
if(n <= 2) return 1LL;
ksm(n - 2); //此时的res为基本数组的幂 ,需乘(1,1),即同行下相加为对应列 数字
ll ans = res.g[1][1] + res.g[2][1];//结合上面就好理解了,ans为乘完(1,1)后第一个数
if(ans >= m) ans %= m;//驱魔
return ans;
}
int main(){
scanf("%d%d",&n,&p);
m=p;
f.g[1][1] = 1;f.g[1][2] = 1;f.g[2][1] = 1;f.g[2][2] = 0;
//f是递推推出来的基本数组,即x^y中x
int endr = (int)solve();
printf("%d",endr);
return 0;
}
相关文章
- 10-05机试学习笔记07 -- 斐波那契数列、素数判定、素数筛选、二分快速幂、分解素因数、常见数学公式总结、规律神器OEIS
- 10-05Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]
- 10-05矩阵快速幂解决斐波那契数问题
- 10-05【poj3070】矩阵乘法求斐波那契数列
- 10-05【洛谷P1349】广义斐波那契数列【矩阵乘法】
- 10-05斐波那契(矩阵乘法+快速幂)
- 10-05快速幂与矩阵乘法的结合(斐波那契数列)
- 10-05AcWing1303. 斐波那契前 n 项和(递推/矩阵快速幂)
- 10-05用Delphi快速计算斐波那契(Fibonacci)数列中的第n个数
- 10-05HDU4549 M斐波那契数列 矩阵快速幂+欧拉函数+欧拉定理