矩阵快速幂
题目
已知数列a
1)n<=k时, a n a_n an=n
2)n>k时, a n = a n − 1 + 2 a n − 2 + 3 a n − 3 + . . . . + k a n − k a_n=a_{n-1}+2a_{n-2}+3a_{n-3}+....+ka_{n-k} an=an−1+2an−2+3an−3+....+kan−k
给n,k求 a n a_n an%(1e9+7)
输入格式
第一行一个数T(1<=T<=30)
接下来T行每行一个n,k
1<=k<=50
1<=n<=1e18
输出格式
每行对应的答案
输入样例
5
2 2
4 3
6 4
50 10
1000000000000000000 30
输出样例
2
10
45
327794974
583778107
思路
r e s = ( 1 2 … … k − 1 k 1 0 … … 0 0 0 1 … … 0 0 … … 0 0 … … 1 0 ) res = \begin{pmatrix} 1 & 2 & …… & k-1&k\\ 1 & 0 & …… & 0&0\\0&1&……&0&0\\ & &……&\\0&0&……&1&0\\\end{pmatrix} res=⎝⎜⎜⎜⎜⎛11002010…………………………k−1001k000⎠⎟⎟⎟⎟⎞
( a k + m a k − 1 + m … a 1 + m ) = r e s m ( a k a k − 1 … a 1 ) \begin{pmatrix} a_{k+m}\\a_{k-1+m}\\…\\a_{1+m}\end{pmatrix}=res^m \begin{pmatrix} a_{k}\\a_{k-1}\\…\\a_{1}\end{pmatrix} ⎝⎜⎜⎛ak+mak−1+m…a1+m⎠⎟⎟⎞=resm⎝⎜⎜⎛akak−1…a1⎠⎟⎟⎞
( a n a n − 1 … a n − k + 1 ) = r e s ( n − k ) ( k k − 1 … 1 ) \begin{pmatrix} a_{n}\\a_{n-1}\\…\\a_{n-k+1}\end{pmatrix}=res^{(n-k)} \begin{pmatrix} k\\k-1\\…\\1\end{pmatrix} ⎝⎜⎜⎛anan−1…an−k+1⎠⎟⎟⎞=res(n−k)⎝⎜⎜⎛kk−1…1⎠⎟⎟⎞
代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1000000007;
struct Matrix{
ll m[55][55];
}res;
Matrix Mul(Matrix A,Matrix B,ll k){
Matrix tmp;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
tmp.m[i][j]=0;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
for(int h=1;h<=k;h++)
tmp.m[i][j]=(tmp.m[i][j]+A.m[i][h]*B.m[h][j])%mod;
return tmp;
}
//求矩阵res的N次方
Matrix QuickPower(long long N,ll k){
//初始化ans
Matrix ans;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
{
if(i==j)
ans.m[i][i]=1;
else
ans.m[i][j]=0;
}
while(N){
if(N&1)
ans=Mul(ans,res,k);
res=Mul(res,res,k);
N=N>>1;
}
return ans;
}
int main(){
int t;
ll n,k,a;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&k);
if(n<=k){
printf("%lld\n",n);
}
else{
for(int i=1;i<=k;i++){
if(i==1){
for(int j=1;j<=k;j++){
res.m[i][j]=j;
}
}
else{
for(int j=1;j<=k;j++){
if(j+1==i){
res.m[i][j]=1;
}
else{
res.m[i][j]=0;
}
}
}
}
Matrix ans=QuickPower(n-k,k);
a=0;
for(int j=1;j<=k;j++){
a=(a+ans.m[1][j]*(k-j+1))%mod;
}
printf("%lld\n",a);
}
}
return 0;
}