一、题目
点此看题
Description
给定数列
前
项,其后每一项满足
其中
为给定数列。请计算
,并将结果对
取模输出。
Input
第 1 行包含两个整数
第 2 行包含 k 个整数
第 3 行包含 k 个整数
Output
一行一个整数
二、解法
很容易想到 的矩阵快速幂,我们现在讲一下 的 常系数齐次线性递推 方法。
首先我们构造一个特征多项式
,根据Cayley-Hamilton定理,有:
是我们的转移矩阵,我们把它当做自变量,
就表示全
矩阵。
设 ,由于 ,所以 ,然后我们可以用类似快速幂套取模的方法算出 ,这一部分的时间复杂度 ,用 优化可做到 。
求出
以后(
是
次多项式),答案的向量为:
由于我们只需要知道
的最上面一项,所以答案为
,这一部分的时间复杂度
。
#include <cstdio>
#include <cstring>
#define int long long
const int MOD = 1e9+7;
const int M = 4005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,k,ans,f[M],h[M];
struct Matrix
{
int a[M];
Matrix() {memset(a,0,sizeof a);}
int& operator [] (const int &i) {return a[i];}
int operator [] (const int &i) const {return a[i];}
Matrix operator * (const Matrix &B) const
{
Matrix res;
for(int i=0;i<k;i++)
for(int j=0;j<k;j++)
res[i+j]=(res[i+j]+a[i]*B[j])%MOD;
for(int i=2*k-2;i>=k;res[i--]=0)
for(int j=1;j<=k;j++)
res[i-j]=(res[i-j]+res[i]*f[j])%MOD;
return res;
}
}R;
Matrix qkpow(Matrix a,int b)
{
Matrix res;
res[0]=1;
while(b>0)
{
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
signed main()
{
n=read();k=read();
for(int i=1;i<=k;i++) f[i]=(read()+MOD)%MOD;
for(int i=0;i<k;i++) h[i]=(read()+MOD)%MOD;
if(n<k)
{
printf("%lld\n",h[n]);
return 0;
}
R[1]=1;
R=qkpow(R,n);
for(int i=0;i<k;i++) ans=(ans+R[i]*h[i])%MOD;
printf("%lld\n",ans);
}