常系数齐次线性递推
矩阵乘法可以被优化成$k^2logn$的。
设转移矩阵是$M$,那么$M$的特征多项式就是 $| \lambda E−M| = \lambda ^ k -\sum_{i=1}^{k}a[i]* \lambda ^{k-i}$
$f(\lambda)$ 是化零多项式,即有 $f(M) = 0$.
把矩阵带进去,得到$M^k=\sum_{i=1}^{k}a[i]*M^{k-i}$,这样我们可以把任意$M^n$表示为$E~M^{k-1}$的和。
$M^n=M^{ \lfloor \frac{n}{2} \rfloor} \times M^{n- \lfloor \frac{n}{2} \rfloor}$,做多项式乘法,得到一个$2k-2$次的多项式,然后不停往前推,直到剩余一个$k-1$次多项式。
最后得到$XM^n=X\sum_{i=0}^{k-1}c_iM^i$,因为$M^iX={h_i,h_{i+1},...,h_{i+k-1}}$,暴力加起来就行了。
大概搞个多项式取模就可以优化成$klogklogn$的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int p=1000000007;
int n,k,f[2010],h[4010];
int rd()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9')
{
if (c=='-') f=-1;
c=getchar();
}
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct mat
{
int a[4010];
void init()
{
a[0]=1;
for (int i=1;i<k;i++) a[i]=0;
}
mat operator * (const mat &mm) const
{
mat ret;
for (int i=0;i<=2*k-2;i++) ret.a[i]=0;
for (int i=0;i<k;i++)
for (int j=0;j<k;j++)
ret.a[i+j]=(ret.a[i+j]+(LL)a[i]*mm.a[j])%p;
for (int i=2*k-2;i>=k;i--)
for (int j=1;j<=k;j++)
ret.a[i-j]=(ret.a[i-j]+(LL)ret.a[i]*f[j])%p;
return ret;
}
}base,res;
int main()
{
int ans=0;
n=rd();
k=rd();
for (int i=1;i<=k;i++)
{
f[i]=rd();
if (f[i]<0) f[i]+=p;
}
for (int i=0;i<k;i++)
{
h[i]=rd();
if (h[i]<0) h[i]+=p;
}
res.init();
base.a[1]=1;
for (n-=k-1;n;n>>=1,base=base*base)
if (n&1) res=res*base;
for (int i=k;i<2*k-1;i++)
for (int j=1;j<=k;j++)
h[i]=(h[i]+(LL)h[i-j]*f[j])%p;
for (int i=0;i<k;i++)
ans=(ans+(LL)res.a[i]*h[k+i-1])%p;
printf("%d\n",ans);
}