矩陣快速冪(模板+例題)
模板
#include<cstdio>
#include<cmath>//pow函式,其實沒啥用
using namespace std;
int n;long long k;
const int N=pow(10,9)+7;
struct node{long long a[105][105];};
node shu,ans,mp;
//shu是輸入的矩陣,ans是所求答案
node matrix(node x,node y){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
mp.a[i][j]=0 ;
for(int p=1;p<=n;p++)
mp.a[i][j]=(mp.a[i][j]+x.a[i][p] * y.a[p][j])%N;
//矩陣乘法
}
return mp;
}
int work(long long k){//矩陣快速冪
while(k){
if(k&1)
ans=matrix(ans,shu);
k>>=1;
shu=matrix(shu,shu);
}
}
int main(){
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
scanf("%d",&shu.a[i][j]);
ans.a[i][i]=1;//任何一個矩陣乘以單位矩陣,其值等於本身;
}
work(k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
printf ("%d ",ans.a[i][j]);
printf("\n");
}
return 0;
}
HDU2842(不水)
題目描述:一根木棒上有n個環(n<=10^9) 第一個環可以隨意取下或者放上 如果前k個環都不在棒子上,且第k+1個環在棒子上,則你可以取下或放上第k+2個環 給出n,求最少需要多少步可以取完棒子上的環?
思路:
1.設f[n]陣列表示取下n個環所需最小次數;
2. 若想讓第n個環被取下,那麼前(n-2)個都要被取下,第(n-1)要掛在環上;這時所需次數為f[n-2]+1;
3. 考慮第(n-1)個環還未取下;而取下第(n-1)個環需要第(n-2)個環掛上,取下第(n-2)個環需要第(n-3)個環掛上…即先要把前(n-2個都取下來);還有f[n-1]它自己;以此類推,取下第(n-1)個環需要次數為f[n-2]+f[n-1];
4. 合併得到遞推公式為:f[n] = f[n-1] + 2 * f[n-2] + 1;
座標系
先挖個坑,有些還沒有搞懂
【題目描述】
小澳在座標系的原點,他可以向上、向左或者向右走。他可以走 n 步,但不能經過相同的點。小澳想知道他有多少種走法。
【題解的想法】:
考慮合法路徑的特點,如果第 i-1 步向上走,那麼第 i 步可以向上、左、右走;如果第 i-1 步向左走,那麼第 i 步可以向上或者向左走;如果第 i-1 步向右走,那麼第 i 步可以向上或者向右走。
用 f[i][0]表示走了 i 步,第 i 步向上走的方案數;f[i][1]表示走了 i 步,第 i 步向左走的方案數;f[i][2]表示走了 i 步,第 i 步向右走的方案數,遞推方程:
f[i][0]=f[i-1][0]+f[i-1][1]+f[i-1][2];
f[i][1]=f[i-1][0]+f[i-1][1];
f[i][2]=f[i-1][0]+f[i-1][2];
進行矩陣乘法優化,可以將時間複雜度降低到 O(logn)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
struct matrix{
ll x[2][2];
matrix(){
memset(x,0,sizeof(x));//賦0的有效方式
}
}ans,a;
matrix operator*(matrix a,matrix b){
matrix res;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j])%mod;
}
return res;
}
int main(){
int n;scanf("%d",&n);n++;
ans.x[0][0]=1;
a.x[0][0]=a.x[0][1]=a.x[1][1]=1;
a.x[1][0]=2;
for(int i=n;i;i>>=1,a=a*a)
if(i&1) ans=ans*a;//過載過運算子後要按照規定的用法使用該符號
printf("%lld\n",ans.x[0][0]);
return 0;
}