BZOJ 4161 Shlw loves matrixI

来源:互联网 发布:海底捞排号软件 编辑:程序博客网 时间:2024/06/03 20:07

特征多项式优化常系数线性递推

详细内容请见《线性递推关系与矩阵乘法 》—叉姐

常见的矩阵乘法可以在O(k3logn)的时间复杂度内算出k阶常系数线性递推数列第 n 项的精确值。我们来研究一下矩阵的特征多项式怎么优化这个东西。

设这个矩阵是M,把这个矩阵的特征多项式搞出来,根据Cayley-hamilton定理以及一些推导,可以得到:iMi 都可以表示成 E,M,M2,,Mk1 的线性组合。

然后我们用类似快速幂的方法就可以快速得到Mn关于 E,M,M2,,Mk1 的线性组合。接着我们要往这个线性组合的多项式里代入h1,h2,,hk,观察 E,M,M2,,Mk1 ,这些矩阵参与到最终代入运算的部分的行都是形如0 010 0的,也就是矩阵里的系数只有一个1,其他都是0,也就是只要代入一个h,而且系数是1很方便,那就直接把h 累加上并且乘上系数即可。

时间复杂度降为O(k2logn)

#include<cstdio>#include<cstring>#define K 2005#define MOD 1000000007using namespace std;namespace runzhe2000{    typedef long long ll;    int n, k, a[K], f[K], base[K<<1], ans[K<<1], z[K<<1];    void mul(int *x, int *y)    {        memset(z, 0, sizeof(z));        for(int i = 0; i < k; i++) for(int j = 0; j < k; j++) (z[i+j] += (ll)x[i] * y[j] % MOD) %= MOD;        for(int i = k+k-2; i >= k; i--)            for(int j = 1; j <= k; j++)                (z[i-j] += (ll)z[i] * a[j] % MOD) %= MOD;        memcpy(x, z, sizeof(z));    }    void main()    {        scanf("%d%d",&n,&k);        for(int i = 1; i <= k; i++) scanf("%d",&a[i]);        for(int i = 1; i <= k; i++) scanf("%d",&f[i]);        base[1] = ans[0] = 1;        for(int lim = n; lim; lim >>= 1)        {            if(lim & 1) mul(ans, base);            mul(base, base);        }         ll r = 0;        for(int i = 1; i <= k; i++)            (r += (ll)f[i] * ans[i-1]) %= MOD;        printf("%lld\n",(r+MOD)%MOD);    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击