矩陣快速冪
先說明一下:看到矩陣快速冪,我先想到的是快速冪,後來感覺差不多。
不會快速冪的可以先看一下這篇:快速冪
廢話不多說,直接上板子:
#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");
else 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;
}
還有三個水題…讀者可以用來練手