附上大神的博客:广义斐波拉契数列循环节点
比赛的时候搞了两种想法:1:暴力找一遍循环节点,应该能在要求的复杂度内找到(并没有写)
2:
这个时候我们的复杂度降到了p*log(2^(32)),然后天真地写了,结果wa了4发,感觉应该不会贵,待会附上代码(依旧TLE)
说说正解:广义斐波拉契数列的循环节:(p-1)*(p+1);
那么问题就转化成了[A]^((p-1)*(p+1)),这个东西直接一次矩阵的快速幂就搞定了,蛋蛋的忧伤,因为这题没有了名额。。。哎。。。
AC代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define N 2
int MOD;
LL p;
struct Matrix{
LL mat[N][N];
///两个矩阵乘法
Matrix operator *(const Matrix& a) const{
Matrix c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++){
LL ssss = ((mat[i][k]*a.mat[k][j])%MOD+MOD)%MOD;
c.mat[i][j] = ((c.mat[i][j]+ssss)%MOD+MOD)%MOD;
}
}
}
return c;
}
///矩阵的幂,用二分的思想写,就是快速幂算法
Matrix operator ^(LL n) const{
Matrix c;
///初始化为单位矩阵
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
c.mat[i][j]=(i==j);
}
}
///就是快速幂
Matrix a = *this;///毕竟直接敲的模板,没运行就写上去了,发现这里少了一个*号
while(n)
{
if(n%2) c=c*a;
a=a*a;
n=n>>1;
}
return c;
}
};
Matrix ss;
///a^n%m
LL quickpow(LL a,LL n,int m){
LL ret = 1;
while(n){
if(n&1) ret = (ret*a)%m;
a = (a*a)%m;
n >>= 1;
}
return ret;
}
int main(){
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
ss.mat[0][0] = 10; ss.mat[0][1] = -1; ss.mat[1][0] = 1; ss.mat[1][1] = 0;
while(T--){
printf("Case #%d: ",++tCase);
LL x;
scanf("%I64d%d",&x,&MOD);
p = (MOD-1)*(MOD+1);
LL r = quickpow(2,x,p);
Matrix st;
st.mat[0][0] = 10; st.mat[0][1] = -1; st.mat[1][0] = 1; st.mat[1][1] = 0;
st = st^r;
LL aaaa = (((st.mat[0][0]*10)%MOD+MOD)%MOD + ((st.mat[0][1]*2)%MOD+MOD)%MOD)%MOD;
if(!aaaa){
printf("%d\n",MOD-1);
}
else
printf("%I64d\n",aaaa-1);
}
return 0;
}
下面是TLE代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define N 2
int MOD;
struct Matrix{
LL mat[N][N];
///两个矩阵乘法
Matrix operator *(const Matrix& a) const{
Matrix c;
memset(c.mat,0,sizeof(c.mat));
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++){
LL ssss = ((mat[i][k]*a.mat[k][j])%MOD+MOD)%MOD;
c.mat[i][j] = ((c.mat[i][j] + ssss)%MOD+MOD)%MOD;
}
}
}
return c;
}
///矩阵的幂,用二分的思想写,就是快速幂算法
Matrix operator ^(LL n) const{
///就是快速幂
Matrix a = *this;///毕竟直接敲的模板,没运行就写上去了,发现这里少了一个*号
while(n--)
{
a=a*a;
}
return a;
}
};
Matrix ans;
int main(){
//freopen("test.in","r",stdin);
//freopen("out.txt","w",stdout);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
LL p;
scanf("%I64d%d",&p,&MOD);
Matrix st;
st.mat[0][0] = 10; st.mat[0][1] = -1; st.mat[1][0] = 1; st.mat[1][1] = 0;
ans.mat[0][0] = 1; ans.mat[0][1] = 0; ans.mat[1][0] = 0; ans.mat[1][1] = 1;
if(MOD == 2){
printf("1\n");
continue;
}
if(!p) {printf("97\n");continue;}
while(p){
LL x = p/MOD,y = p%MOD;
Matrix res;
res = st^y;
ans = ans*res;
st = st^x;
p /= MOD;
}
LL ppp = (((ans.mat[0][0] * 10)%MOD+MOD)%MOD + ((ans.mat[0][1]*2)%MOD+MOD)%MOD)%MOD;
if(!ppp){
printf("%I64d\n",MOD-1);
}
else printf("%I64d\n",ppp-1);
}
return 0;
}