bzoj 4161 Shlw loves matrix I

常系数线性递推.

  • 矩阵快速幂是 $O(k^3\cdot logn)$ 的,不够优秀.观察式子(后续用 $a$ 代替 $h$ ,用 $f$ 代替 $a$ ),

$$
a_n=\sum_{i=1}^k f_i\cdot a_{n-i}
$$

  • 注意到任意一项 $a_i$ 都可以被 $\lbrace a_0,a_1,\dots,a_{k-1} \rbrace$ 线性表示,考虑已知 $a_n$ 的线性表示,如何求得 $a_{2n}$ 的线性表示.这里需要利用一个性质,若:

$$
a_n=\sum_{i=0}^{k-1}b_i\cdot a_i
$$

  • 则,

$$
a_{n+x}=\sum_{i=0}^{k-1}b_i\cdot a_{i+x}
$$

  • 证明应该是显然的,相当于将 $a_x$ 看做这个数列的首项,递推式都是一样的,所以对应系数也是一样的.
  • 于是,连续用 $2$ 次该性质可得,

  • 这样就用 $\lbrace a_0,a_1,a_2,\dots,a_{2k-2} \rbrace$ 线性表示了 $a_{2n}$ .那么只需要求得 $\lbrace a_k,a_{k+1},a_{k+2},\dots,a_{2k-2} \rbrace$ 的线性表示,然后代进去即可.
  • 像快速幂那样做下去,只用做 $logn$ 次.时间复杂度 $O(k^2\cdot logn)$ .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int P=1e9+7;
inline int add(int a,int b)
{
return (a + b) % P;
}
inline int mul(int a,int b)
{
return 1LL * a * b % P;
}
const int MAXN=2e3+10;
int n,k,tmp[MAXN<<1];
void Mul(int *a,int *b,int *f)
{
memset(tmp,0,k<<3);
for(int i=0;i<k;++i)
for(int j=0;j<k;++j)
tmp[i+j]=add(tmp[i+j],mul(a[i],b[j]));
for(int i=2*k-2;i>=k;--i)
for(int j=0;j<k;++j)
tmp[i-j-1]=add(tmp[i-j-1],mul(tmp[i],f[j]));
memcpy(a,tmp,k<<2);
}
int base[MAXN],ans[MAXN];
int solve(int *a,int *f,int N)
{
if(N<k)
return a[N];
base[1]=ans[0]=1;
while(N)
{
if(N&1)
Mul(ans,base,f);
Mul(base,base,f);
N>>=1;
}
int res=0;
for(int i=0;i<k;++i)
res=add(res,mul(a[i],ans[i]));
return res;
}
int f[MAXN],a[MAXN];
int main()
{
n=read(),k=read();
for(int i=0;i<k;++i)
f[i]=add(read(),P);
for(int i=0;i<k;++i)
a[i]=add(read(),P);
cout<<solve(a,f,n)<<endl;
return 0;
}