前
这一篇blog从有想法到写完所有代码总共花了好长好长时间
虽然最后可能在这篇博文里体现不出来,但是真的好难
快速幂和矩阵快速幂比较简单,稍微带过直接放代码
斐波那契数列才是这次的主角
快速幂
位运算比较快 用了>>和&
LL qpow(LL a , LL b) {
if(b==0)
return 1;
LL c = qpow(a,b>>1)%k;
if(b&1)
return c*c%k*a%k;
return c*c%k;
}
矩阵快速幂
重载一下乘法,再写几个结构体函数,其实其他和快速幂一样
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 76
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
inline LL read() {
LL x=0,f=1;char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-f;c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
return x*f;
}
LL n , k;
struct Mat {
LL num[105][105];
Mat() {
memset(num , 0 , sizeof(num));
}
void init() {
Fo(i,1,n)
num[i][i] = 1;
}
void print() {
Fo(i,1,n) {
Fo(j,1,n)
printf("%d ",num[i][j]);
printf("\n");
}
}
};
Mat A , E;
Mat operator * (const Mat &x , const Mat &y) {
Mat z;
Fo(i,1,n)
Fo(j,1,n)
Fo(k,1,n)
z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
return z;
}
Mat qpow(Mat x , LL y) {
if(y==0)
return E;
if(y==1)
return x;
Mat z = qpow(x , y>>1);
if(y&1)
return z*z*x;
return z*z;
}
int main() {
E.init();
n=read();k=read();
Fo(i,1,n)
Fo(j,1,n)
A.num[i][j]=read();
qpow(A,k).print();
return 0;
}
斐波那契数列及其推广
有几种形式:(目前遇到的,以下分别标号123)
f [ 1 ] = 1 , f [ 2 ] = 1 , f [ i ] = f [ i − 1 ] + f [ i − 2 ] f[1]=1,f[2]=1,f[i]=f[i-1]+f[i-2] f[1]=1,f[2]=1,f[i]=f[i−1]+f[i−2]
f [ 1 ] = 1 , f [ 2 ] = 1 , f [ i ] = A × f [ i − 1 ] + B × f [ i − 2 ] f[1]=1,f[2]=1,f[i]=A×f[i-1]+B×f[i-2] f[1]=1,f[2]=1,f[i]=A×f[i−1]+B×f[i−2]
f [ 1 ] = C , f [ 2 ] = D , f [ i ] = A × f [ i − 1 ] + B × f [ i − 2 ] f[1]=C,f[2]=D,f[i]=A×f[i-1]+B×f[i-2] f[1]=C,f[2]=D,f[i]=A×f[i−1]+B×f[i−2]
分别对应题目:
LG1720
HDU1005
WIT新生赛J题
第1种
就是常规的斐波那契数列,矩阵快速幂做法如下图
其实没必要非得用最后一行的公式,用倒数第二行的公式或许更能变通(比如第2种)
代码实现:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 1000000007
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
LL x=0,f=1;char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-f;c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
return x*f;
}
LL n;
struct Mat {
LL num[6][6];
Mat() {
Ms(num,0);
}
void init() {
num[1][1]=num[1][2]=num[2][1]=1;
num[2][2]=0;
}
void E() {
Fo(i,1,n)
num[i][i]=1;
}
LL fib() {
return num[2][1];
}
};
Mat E , A;
Mat operator * (const Mat &x , const Mat &y) {
Mat z;
Fo(i,1,2)
Fo(j,1,2)
Fo(k,1,2)
z.num[i][j]=z.num[i][j]+x.num[i][k]*y.num[k][j];
return z;
}
Mat qpow(Mat x , LL y) {
if(!y) return E;
if(y==1) return x;
Mat z=qpow(x,y>>1);
if(y&1)
return z*z*x;
return z*z;
}
int main() {
n=read();
E.E(); A.init();
printf("%lld.00",qpow(A,n).fib());
return 0;
}
第2种
就是第1种的变通(画图有点丑)
代码实现
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define mod 7
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
LL x=0,f=1;char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-f;c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
return x*f;
}
LL A , B , n;
struct Mat {
LL num[15][15];
Mat() {
Ms(num,0);
}
void init(LL a , LL b) {
num[1][1]=a; num[1][2]=1;
num[2][1]=b; num[2][2]=0;
}
void K() {
num[1][1]=num[1][2]=1;
}
void E() {
Fo(i,1,n)
num[i][i]=1;
}
LL fib() {
return num[1][1]%mod;
}
};
Mat E , K , P;
Mat operator * (const Mat &x , const Mat &y) {
Mat z;
Fo(i,1,2)
Fo(j,1,2)
Fo(k,1,2)
z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
return z;
}
Mat qpow(Mat x , LL y) {
if(!y) return E;
if(y==1) return x;
Mat z=qpow(x,y>>1);
if(y&1)
return z*z*x;
return z*z;
}
int main() {
E.E(); K.K();
while(1) {
A=read(); B=read(); n=read();
if(A==0&&B==0&&n==0)
break;
if(n==1||n==2) {
printf("1\n");
continue;
}
P.init(A,B);
printf("%lld\n",(K*qpow(P,n-2)).fib()%mod);
}
return 0;
}
第3种
这个坑点有点多,但是学到一种求大数的斐波那契数列的方法
就是先求底数矩阵的个位数次方,然后底数矩阵自己求10次方,再做十位依次向前
因为我的做法是求得n-1次方,所以有很大的坑点
所以 直接用n就行!最好别写n-1因为要判断0啥的有亿点点麻烦
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define fin freopen("data.txt","r",stdin)
#define INF 2147483647
#define eps 1e-7
#define L 100005
#define Fo(i,a,b) for(LL i=(a),_=(b); i<=_; i++)
#define Ro(i,b,a) for(LL i=(b),_=(a); i>=_; i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
inline LL read() {
LL x=0,f=1;char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-f;c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48ll),c=getchar();
return x*f;
}
string n;
LL A , B , C , D , mod , len , num[500005] , flag;
struct Mat {
int num[10][10];
Mat() {
Ms(num,0);
}
void K(LL a , LL b) {
num[1][1]=a; num[1][2]=b;
num[1][3]=num[2][1]=num[3][3]=1;
}
void P(LL f0 , LL f1 , LL f2) {
num[1][1]=f2;
num[1][2]=num[2][1]=f1;
num[2][2]=f0;
num[3][1]=num[3][2]=num[3][3]=7;
}
void E() {
Fo(i,1,3)
num[i][i]=1;
}
LL fib() {
return num[1][1]%mod;
}
};
Mat K , P , ans;
Mat operator * (const Mat &x , const Mat &y) {
Mat z;
Fo(i,1,3)
Fo(j,1,3)
Fo(k,1,3)
z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
return z;
}
Mat E;
Mat qpow(Mat x , LL y) {
if(!y) return E;
if(y==1) return x;
Mat z=qpow(x,y>>1);
if(y&1)
return z*z*x;
return z*z;
}
int main() {
A=read(); B=read(); C=read(); D=read(); cin>>n; mod=read();
E.E(); K.K(A,B); P.P(D-C,C,D); ans.E();
len = n.length();
Fo(i,0,len-1)
num[i+1]=n[i]-'0';
Ro(i,len,1) {
if(i==len) {
LL top=i;
while(num[top]==0) {
top--;
flag = 1;
}
if(!flag) {
ans=qpow(K,num[i]-1);
K=qpow(K,10);
} else {
num[top]--;
Fo(j,top+1,len)
num[j]=9;
ans = ans * qpow(K,num[i]);
K = qpow(K,10);
}
continue;
}
ans = ans * qpow(K,num[i]);
K = qpow(K,10);
}
ans=ans*P;
printf("%lld",ans.fib()%mod);
return 0;
}
后
好了,这篇blog会一直更新,遇到新的类型就会更新上去,希望能对你对我有所帮助