bzoj4161 (k^2logn求线性递推式)

分析:

  我们可以写把转移矩阵A写出来,然后求一下它的特征多项式,经过手动计算应该是这样的p(x)=$x^k-\sum\limits_{i=1}^ka_i*x^{k-i}$

  根据Cayley-Hamilton定理可得,p(A)=0

  他表示$A^n = f(A) * p(A) + g(A)$

  第一项的值是0,所以即$A^n=g(A)$,其中f(A) g(A)都是关于A的多项式,f(A)是多项式除法的商,g(A)是余数

  我们考虑$x^n$这个多项式,我们去求出它对于$p(A)$的余数多项式$g(A)$,那么$A^n$就等价于了$g(A)$,注意到新的多项式次数就很低了,不超过k-1

  我们要求的是$A^nH=\sum\limits_{i=0}^{k-1}c_i*A^i*H$的第一个元素,注意到$A^i*H$相当于把H又递推了i次

  所以结果等价于$A^nH=\sum\limits_{i=0}^{k-1}c_i*A^i*H$

  时间复杂度$O(k^2 log n)$,但常数很大

  中间的多项式取模和递推可以用FFT来优化,但常数更巨大

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=4000,mod=1000000007;
 4 int a[maxn+5],p[maxn+5],ans[maxn+5],num[maxn+5];
 5 int h[maxn+5],tmp[maxn+5];
 6 int n,k;
 7 void mul(int *a,int *b,int *ans)
 8 {
 9     for(int i=0;i<=2*k;++i) tmp[i]=0;
10     for(int i=0;i<k;++i)
11         for(int j=0;j<k;++j)
12             tmp[i+j]=(tmp[i+j]+1LL*a[i]*b[j])%mod;
13     for(int i=2*k-2;i>=k;--i)
14     {
15         for(int j=k-1;j>=0;--j)
16             tmp[i-k+j]=(tmp[i-k+j]-1LL*tmp[i]*p[j])%mod,tmp[i-k+j]=(tmp[i-k+j]+mod)%mod;
17         tmp[i]=0;
18     }
19     for(int i=0;i<k;++i) ans[i]=tmp[i];
20 }
21 int main()
22 {
23     scanf("%d%d",&n,&k);
24     for(int i=1;i<=k;++i) scanf("%d",&a[i]);
25     for(int i=0;i<k;++i) scanf("%d",&h[i]);
26     p[k]=1;
27     for(int i=1;i<=k;++i) p[k-i]=mod-a[i];
28     for(int i=k;i<2*k;++i)
29         for(int j=1;j<=k;++j)
30         {
31             h[i]=h[i]+1LL*h[i-j]*a[j]%mod;
32             h[i]%=mod;
33         }
34     if(n<2*k) return 0*printf("%d\n",h[n]);
35     int b=n-k+1;
36     num[1]=1,ans[0]=1;
37     while(b)
38     {
39         if(b&1) mul(ans,num,ans);
40         mul(num,num,num);
41         b>>=1;
42     }
43     long long res=0;
44     for(int i=0;i<k;++i) res=(res+1LL*ans[i]*h[i+k-1])%mod;
45     printf("%lld\n",(res+mod)%mod);
46     return 0;
47 }
View Code

 

posted @ 2018-02-15 01:09  Chellyutaha  阅读(1046)  评论(0编辑  收藏  举报