#include
#include//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;
}
英文版原题
题目描述:一根木棒上有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
#include
#include
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;
}