矩阵其实就是一个个线性方程组的组合,所以可以利用矩阵来进行加速
矩阵乘法:
直接贴板子
struct node
{
long long n,m;
long long a[105][105];
node operator * (const node &b)
{
node c;
c.n=n;
c.m=b.m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=b.m;j++)
{
c.a[i][j]=0;
for(int k=1;k<=m;k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
}
}
return c;
}
};
矩阵加速:
知道了关于矩阵就是一个个线性方程组之后,我们就考虑用矩阵进行优化。
引入两个概念:初始矩阵和加速矩阵
顾名思义,对初始矩阵和加速矩阵进行处理后能以较快的时间得到答案
经典例题:
大家都知道 Fibonacci 数列吧。求Fibonacci的第n项%m的值。
n<=2*1e9
m<=1e9+10
空间:512MB
时间:1000ms
思路:
最容易想到的是递推,考虑用数组存下每一项的值,显而易见,空间会炸。
考虑递推式f(i)=f(-1)+f(i-2);,发现每一项只与前两项有关,空间就这么压缩下来了,但是时间会炸
考虑正解,设矩阵{f[i],f[i+1]},为初始矩阵,接着就是加速矩阵的设计,现状态的a[1][1],就是上一个状态的a[1][2],现状态的
a[1][2]就是上一个状态的a[1][1]+a[1][2];加速矩阵即为{{0,1},{1,1}}
也就是说,将初始矩阵乘以n-1个加速矩阵,我们就得到了答案,
考虑如何快速得出n-1个加速矩阵的成绩,自然会想到快速幂
代码实现并不难
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
void read(int &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<0)
{
putchar('-');
write(-x);
return;
}
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
int n,mod;
struct node
{
long long n,m;
long long a[105][105];
node(){memset(a,0,sizeof(a));}
node operator * (const node &b)
{
node c;
c.n=n;
c.m=b.m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=b.m;j++)
{
c.a[i][j]=0;
for(int k=1;k<=m;k++)
{
c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mod;
}
}
}
return c;
}
void pr()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
write(a[i][j]);
putchar(' ');
}
putchar('\n');
}
}
}a,b,c;
node qkpow(node x,int y)
{
if(y==1)
return x;
node t=qkpow(x,y/2);
t=t*t;
if(y%2==1)
t=t*x;
return t;
}
int main()
{
read(n);
read(mod);
if(n<=2)
{
cout<<1%mod;
return 0;
}
a.n=1;
a.m=2;
a.a[1][1]=1;
a.a[1][2]=1;
b.n=2;
b.m=2;
b.a[1][2]=b.a[2][1]=b.a[2][2]=1;
b.a[1][1]=0;
c=a*b;
c=a*qkpow(b,n-1);
cout<<c.a[1][1];
return 0;
}