您的位置:首页 > 其它

矩阵快速幂(14)

2020-02-02 19:45 225 查看

矩阵快速幂

先说明一下:看到矩阵快速幂,我先想到的是快速幂,后来感觉差不多。
不会快速幂的可以先看一下这篇:快速幂
废话不多说,直接上板子:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=10000;  //先不用管这个,一做题就明白了
int f=2;
struct node
{
ll materix[5][5];
};

node mul(node a,node b)  //矩阵乘法
{
node res;
memset(res.materix,0,sizeof res.materix);
for(int i=1;i<=f;i++)
for(int j=1;j<=f;j++)
for(int k=1;k<=f;k++)
res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
return res;
}

node ksm(node a,ll b)    //快速幂
{
node ans;
memset(ans.materix,0,sizeof ans.materix);
for(int i=1;i<=f;i++)
ans.materix[i][i]=1;
while(b)
{
if(b&1)
ans=mul(ans,a);
b>>=1;
a=mul(a,a);
}
return ans;
}

大体就是上面那套板子,按照小编目前短浅的理解,矩阵快速幂的难度在于找到最初始的矩阵和乘的矩阵…
来几个板子题:

传送门:Fibonacci POJ - 3070

很明显直接算不现实,这时候就得用到矩阵快速幂,这里就是那个mod的作用

//#include<bits/stdc++.h>
#include <iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int mod=10000;
int f=2;
struct node
{
ll materix[5][5];
};

node mul(node a,node b)  //矩阵乘法
{
node res;
memset(res.materix,0,sizeof res.materix);
for(int i=1;i<=f;i++)
for(int j=1;j<=f;j++)
for(int k=1;k<=f;k++)
res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
return res;
}

node ksm(node a,ll b)
{
node ans;
memset(ans.materix,0,sizeof ans.materix);
for(int i=1;i<=f;i++)
ans.materix[i][i]=1;
while(b)
{
if(b&1)
ans=mul(ans,a);
b>>=1;
a=mul(a,a);
}
return ans;
}

int main()
{
ll N;
while(cin>>N&&N!=-1)
{
if(N==1||N==2)
printf("1\n");
if(N==0)
printf("0\n");
else
{
node a,b;
a.materix[1][1]=1; a.materix[1][2]=1;
a.materix[2][1]=1; a.materix[2][2]=0;   //a是那个幂矩阵,
b.materix[1][1]=1; b.materix[1][2]=0;
b.materix[2][1]=1; b.materix[2][2]=0;   //b是最初始的矩阵
//假如a*a*a*b就是a^3*b,所以先求用快速幂求a的三次方,再用结果和b相乘
//注意乘的顺序,矩阵相乘a*b!=b*a,顺序不能搞错
//这里个人有个小诀窍,因为.f(n)=a*f(n-1)+b*f(n-2)+c,所以前边的那个应该是构造矩阵
node ans = ksm(a ,N-2);  //从3开始,所以-2
ans = mul(ans ,b) ;
printf("%d\n",ans.materix[1][1] ) ;
}
}
return 0;
}

传送门: Tr A HDU - 1575

一模一样的板子题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
int mod=9973;
struct node
{
ll materix[11][11];
};
node mul(node a,node b)  //矩阵乘法
{
node res;
memset(res.materix,0,sizeof res.materix);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
return res;
}
node ksm(node a,ll b)
{

node ans;
memset(ans.materix,0,sizeof ans.materix);
for(int i=0;i<n;i++)
ans.materix[i][i]=1;
while(b)
{
if(b&1)
ans=mul(ans,a);
b>>=1;
a=mul(a,a);
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>k;
node c;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>c.materix[i][j];

node ans=ksm(c,k);
int sum=0;
for(int i=0;i<n;i++)
sum=sum+ans.materix[i][i]%mod;
printf("%d\n",sum%mod);
}
return 0;
}

传送门: A Simple Math Problem HDU - 1757

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll k,m;
int aa[15];
struct node
{
ll materix[15][15];
};
node mul(node a,node b)  //矩阵乘法
{
node res;
memset(res.materix,0,sizeof res.materix);
for(int i=1;i<=10;i++)
for(int j=1;j<=10;j++)
for(int k=1;k<=10;k++)
res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%m;
return res;
}
node ksm(node a,ll b)
{
node ans;
memset(ans.materix,0,sizeof ans.materix);
for(int i=1;i<=10;i++)
ans.materix[i][i]=1;
while(b)
{
if(b&1)
ans=mul(ans,a);
b>>=1;
a=mul(a,a);
}
return ans;
}

int main()
{
while(~scanf("%lld %lld",&k,&m))
{
if(k<10)
{
cout<<k%m<<endl;
continue;
}
else
{
node a,b;
for(int i=0;i<=15;i++)
for(int j=0;j<=15;j++)
a.materix[i][j]=b.materix[i][j]=0;

for(int i=1;i<=10;i++)
cin>>a.materix[1][i];
for(int i=1;i<=9;i++)
a.materix[i+1][i]=1;

for(int i=1;i<=10;i++)
b.materix[i][1]=10-i;

node ans=ksm(a,k-9);
ans=mul(ans,b);
printf("%d\n",ans.materix[1][1]%m);
}
}
return 0;
}

传送门: Recursive sequence HDU - 5950(矩阵的构造)

这应该是一个简单的矩阵构造,希望读者能认认真真的学会如何构造一个矩阵。
这个题的构造难在构造矩阵当时构造出来后就懒得写板子了,所以直接CV代码。
关于这个题,读者应该去百度如何构造矩阵,去学习多种矩阵的构造方法以防万一。

#include<stdio.h>
#include<string.h>
using namespace std;

#define ll long long
const ll maxn = 7;
const ll mod = 2147493647;

struct mat
{
ll m[maxn][maxn];
};

mat operator *(mat x, mat y)
{
mat ret;
for(int i = 0; i < maxn; i++)
{
for(int j = 0; j < maxn; j++)
{
ret.m[i][j] = 0;
for(int k = 0; k < maxn; k++)
{
ret.m[i][j] = (x.m[i][k] * y.m[k][j] + ret.m[i][j]) % mod;
}
}
}
return ret;
}

mat pow_mat(mat a, ll fuck)
{
mat ret;
memset(ret.m,0,sizeof(ret.m));
for(int i = 0; i < maxn; i++) ret.m[i][i] = 1;
while(fuck)
{
if(fuck&1) ret = ret*a;
a = a*a;
fuck >>= 1;
}
return ret;
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll f1, f2, m;
scanf("%lld%lld%lld",&m,&f1,&f2);
if(m == 1) printf("%lld\n",f1);
else if(m == 2) printf("%lld\n",f2);
else
{
mat a;
memset(a.m,0,sizeof(a.m));
a.m[0][0] = f2;
a.m[1][0] = f1;
a.m[2][0] = 1;
a.m[3][0] = 2;
a.m[4][0] = 4;
a.m[5][0] = 8;
a.m[6][0] = 16;
mat b =
{
1, 2, 1, 4, 6, 4, 1,
1, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 0,
0, 0, 1, 2, 1, 0, 0,
0, 0, 1, 3, 3, 1, 0,
0, 0, 1, 4, 6, 4, 1
};
a = pow_mat(b,m-2)*a;
printf("%lld\n",a.m[0][0]);
}
}
return 0;
}

还有三个水题…读者可以用来练手

传送门:1126 求递推序列的第N项

传送门:1113 矩阵快速幂

传送门:1137 矩阵乘法

  • 点赞
  • 收藏
  • 分享
  • 文章举报
〆℡小短腿走快点ゝ 发布了30 篇原创文章 · 获赞 1 · 访问量 1414 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: