今天看了一下cgy杯,里面涉及的算法很多,其中有一个就是在蓝桥杯,校赛等多次比赛中坑了我的矩阵快速幂,然而我现在还不会,毕竟已经学了线代,今天把它总结一下叭。
1.快速幂
解释
首先,快速幂的目的就是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn),快了好多好多。它的原理如下:
假设我们要求a^b ,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1) 例如当b==11时a11=a(2^0 + 2^1+ 2^3) ,11的二进制是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,因此,我们将a¹¹转化为算 a2^0* a2^1* a2^3,也就是a1* a2* a8 ,看出来快的多了吧原来算11次,现在算三次,但是这三项貌似不好求的样子....不急,下面会有详细解释。
**由于是二进制,很自然地想到用位运算这个强大的工具:&和>> &运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1==0为偶,x&1==1为奇。 >>运算比较单纯,二进制去掉最后一位,不多说了,先放代码再解释。 **
模板
int quickPower(int a, int b)//是求a的b次方
{
int ans = 1, base = a;//ans为答案,base为a^(2^n)
while(b > 0)//b是一个变化的二进制数,如果还没有用完,也可以改成while(b)
{
if(b & 1)//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是:
ans *= base;//把ans乘上对应的a^(2^n)
base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))
b >>= 1;
//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。结合上面b & 1食用更佳
}
return ans;
}
实现
#include
using namespace std;
long long int k;
long long int quickPower(long long int a,long long int b)
{
long long int ans=1,base=a;
while(b>0)
{
if(b&1)
ans=ans*base%k;
base=base*base%k;
b>>=1;
}
return ans;
}
int main()
{
long long int b,p;
cin>>b>>p>>k;
printf("%lld^%lld mod %lld=%d",b,p,k,quickPower(b,p)%k);
return 0;
}
2.模板【矩阵快速幂】
#include
using namespace std;
#define mod 1000000007
#define ll long long
//结构体矩阵
struct matric{
ll m[101][101];
};
matric a,e;//a是输入矩阵,e是单位阵
ll n,p;
//矩阵乘法
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
c.m[i][j]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
return c;
}
//矩阵快速幂
matric pow(matric x,ll y){
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main()
{
cin>>n>>p;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a.m[i][j];
for(int i=1;i<=n;i++)
e.m[i][i]=1;
matric ans=pow(a,p);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<
3.Fibonacci
Emmm 如何应用到斐波那契捏
只要第一步确定了它最初的数列是怎么样的就行了
//#include
#include
#include
using namespace std;
#define mod 10000
#define ll long long
//结构体矩阵
struct matric{
ll m[3][3];
};
matric a,e;//a是输入矩阵,e是单位阵
ll n=2,p;
//矩阵乘法
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
c.m[i][j]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
return c;
}
//矩阵快速幂
matric pow(matric x,ll y){
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main()
{
while(cin>>p&&p!=-1){
a.m[1][1]=a.m[2][1]=a.m[1][2]=1;
a.m[2][2]=0;
for(int i=1;i<=n;i++)
e.m[i][i]=1;
matric ans=pow(a,p);
cout<
4.CGY杯
CGYtql
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int f[6]={0,8,6,5,3,2};
struct matric{
ll m[6][6];
};
matric a,e;//input a,danwei e
//矩阵乘法
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
c.m[i][j]=0;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
for(int k=1;k<=5;k++){
c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
}
return c;
}
//矩阵快速幂
matric pow(matric x,ll y){
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main(){
int n;
for(int i=1;i<=5;i++)
e.m[i][i]=1;
while(cin>>n&&n!=0){
// memset(a,0,sizeof(a));
int ans1=0;
int ans2=0;
if(n<6){
cout<
修订过后
注意longlong
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int f[6]={0,8,6,5,3,2};
struct matric{
ll m[6][6];
};
matric a,e;//input a,danwei e
//矩阵乘法
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
c.m[i][j]=0;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
for(int k=1;k<=5;k++){
c.m[i][k]=(c.m[i][k]%mod+x.m[i][j]*y.m[j][k]%mod)%mod;
}
return c;
}
//矩阵快速幂
matric pow(matric x,ll y){
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main(){
long long int n;
for(int i=1;i<=5;i++)
e.m[i][i]=1;
while(cin>>n&&n!=0){
// memset(a,0,sizeof(a));
long long int ans1=0;
long long int ans2=0;
if(n<6){
cout<
这个代码可以使res初始化为零矩阵
Matrix operator * (const Matrix &a){
Matrix res;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
for(int k=1;k<=5;k++)
res.m[i][k]=(res.m[i][k]+(m[i][j]*a.m[j][k])%mod)%mod;
return res;
}
5.Kiki & Little Kiki 2
有题目可知,如果左边的灯是开的,则这个灯的状态就要改变,从而可以找出一个规律a[n]=(a[n-1]+a[n])%2, a[1]=(a[1]+a[n])%2
#include
#include
#include
#include
#define ll long long
using namespace std;
int m,num,sum[101];
struct matric{
int n[101][101];
};
matric e,a,b;//a is 初始 , b is input
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
c.n[i][j]=0;
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
for(int k=1;k<=num;k++)
c.n[i][j]=(c.n[i][j]+x.n[i][k]*y.n[k][j])%2;
return c;
}
//quick
matric pow(matric x,int y){//y is time
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main(){
//freopen("data","r",stdin);
char ch[101];
while(cin>>m){
scanf("%s",ch);
num=strlen(ch);
memset(b.n,0,sizeof(b.n));
memset(a.n,0,sizeof(a.n));
for(int i=1;i<=num;i++){
b.n[i][1]=ch[i-1]-'0';
}
for(int i=1;i<=num;i++){
e.n[i][i]=1;
}
a.n[1][1]=a.n[1][num]=1;
for(int i=2;i<=num;i++)
a.n[i][i-1]=a.n[i][i]=1;
matric ans=pow(a,m);
ans=Multi(ans,b);
for(int i=1;i<=num;i++)
{
cout<
- 这里由于没有memset导致输出错误;
- y>>=1;这里总是会少了=;
- b.n[i][1]=ch[i-1]-'0';傻傻的跟着别人把写成了0;
6.G-又见斐波那契
递推公式
将输入的n+1后进行观察取系数
f[i+1] = f[i] + f[i--1] + i^3 + i^2 + i + 1
f[i] = f[i]
(i+1)^3 = i^3 + 3i^2 + 3i + 1
(i+1)^2 = i^2 + 2*i + 1
(i+1) = i + 1
1 = 1
因此在最后带进去的实参是n-1;
#include
#include
#include
#include
#define ll long long
#define mod 1000000007
using namespace std;
ll m,num;
ll a[7][7]={
0,0,0,0,0,0,0,
0,1,1,1,1,1,1,
0,1,0,0,0,0,0,
0,0,0,1,3,3,1,
0,0,0,0,1,2,1,
0,0,0,0,0,1,1,
0,0,0,0,0,0,1
};
struct matric{
ll n[7][7];
};
matric e,b;//a is 初始 , b is input
matric Multi(matric x,matric y){
matric c;
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
c.n[i][j]=0;
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
for(int k=1;k<=6;k++)
c.n[i][j]=(c.n[i][j]+x.n[i][k]*y.n[k][j])%mod;
return c;
}
//quick
matric pow(matric x,ll y){//y is time
matric ans=e;
while(y){
if(y&1)
ans=Multi(ans,x);
x=Multi(x,x);
y>>=1;
}
return ans;
}
int main(){
//freopen("data","r",stdin);
int T;
cin>>T;
matric base;
base.n[1][1]=1,base.n[2][1]=0,base.n[3][1]=8;
base.n[4][1]=4,base.n[5][1]=2,base.n[6][1]=1;
for(int i=1;i<=6;i++)
e.n[i][i]=1;
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
b.n[i][j]=a[i][j];
while(T--){
cin>>num;
matric ans = pow(b,num-1);
ans=Multi(ans,base);
cout<