玄学小记.2 ~ bzoj 4162: shlw loves matrix II

我们需要求(g(P)),其中(g)是一个只有一项的多项式

暴力是(n ^ 3 log k)的,显然过不去

怎么办?

特征方程优化矩阵快速幂~

考虑方程(|xI - P| = 0),把det展开后可以得到一个方程(f(x) = 0),这个方程称为(P)的特征方程,(f)称为(P)的特征多项式

基于某个厉害的定理,有(f(P) = 0),也就是说矩阵(P)是特征方程的一个解

于是有(g(P) = (g mod f)(P)),由于(f)的次数只有(n),而且多项式取模的复杂度很容易做到(O(n ^ 2))

因此只要算出特征多项式就可以(O(n ^ 4 + n ^2 log k))计算

那么怎么求出特征多项式呢?

牛顿恒等式~

对于多项式(F(x) = sum_{i = 0}^{n} c_{n-i} x^i)

若有方程(F(x) = 0),它显然有(n)个根 (x_1, x_2 ... x_n),令(s_{k} = sum_{i = 1}^{n} x_{i}^k)

则有:

当(1 leq k leq n)时,有(sum_{i = 0}^{k - 1} c_{i} * s_{k - i} +c_{k} * k = 0) 

当(n < k)时,有(sum_{i = 0}^{n} c_{i} * s_{k - i} = 0)

这玩意对于矩阵同样成立~

基于另一个厉害的定理,特征方程(f(x) = 0)的根(lambda_{i})满足:(s_k = sum lambda _{i}^{k} = tr(P^k))

于是可以通过牛顿恒等式解出特征方程每一项的系数~

这样就可以(O(n^4))解出特征多项式了了……

时间复杂度(O(n ^ 4 + n ^2 log k))

#include <bits/stdc++.h>
using namespace std;

// #define int long long
const int N = 55;
const int MOD = 1000000007;
char st[20000]; int k;
struct mat
{
    int d[N][N];
    mat()
    {
        memset(d, 0, sizeof d);
    }
} X, P[N], I, ans;
mat operator * (mat a, mat b)
{
    mat c;
    for (int i = 0; i < k; ++ i)
        for (int j = 0; j < k; ++ j)
            for (int p = 0; p < k; ++ p)
                c.d[i][j] = (1ll * a.d[i][p] * b.d[p][j] + c.d[i][j]) % MOD;
    return c;
}
mat operator * (mat a, int b)
{
    mat c;
    for (int i = 0; i < k; ++ i)
        for (int j = 0; j < k; ++ j)
            c.d[i][j] = 1ll * a.d[i][j] * b % MOD;
    return c;
}
mat operator + (mat a, mat b)
{
    mat c;
    for (int i = 0; i < k; ++ i)
        for (int j = 0; j < k; ++ j)
            c.d[i][j] = (a.d[i][j] + b.d[i][j]) % MOD;
    return c;
}
int powi(int a, int b)
{
    int c = 1;
    for (; b; b /= 2, a = 1ll * a * a % MOD)
        if (b & 1) c = 1ll * c * a % MOD;
    return c;
}
int S[N], C[N];

struct poly
{
    int d[N * 2];
    poly ()
    {
        memset(d, 0, sizeof d);
    }
} pI, pS;
poly operator * (poly a, poly b)
{
    poly c;
    for (int i = 0; i < k; ++ i)
        for (int j = 0; j < k; ++ j)
            c.d[i + j] = (c.d[i + j] + 1ll * a.d[i] * b.d[j]) % MOD;
    for (int i = k + k - 2; i >= k; -- i)
    {
        int v = c.d[i];
        for (int j = 0; j <= k; ++ j)
            c.d[i - j] = (c.d[i - j] - 1ll * v * C[j] % MOD + MOD) % MOD;
    }
    return c;
}
poly powi(poly a, char b[], int l)
{
    poly c = pI;
    for (int i = l - 1; ~i; -- i, a = a * a)
        if (b[i] == '1')
            c = c * a;
    return c;
}
signed main()
{
    scanf("%s%d", st, &k);
    int l = strlen(st);
    for (int i = 0; i < k; ++ i) I.d[i][i] = 1;
    pI.d[0] = 1;
    for (int i = 0; i < k; ++ i)
        for (int j = 0; j < k; ++ j)
            scanf("%d", &X.d[i][j]);
    P[0] = I; C[0] = 1;
    for (int i = 1; i <= k; ++ i)
    {
        P[i] = P[i - 1] * X;
        for (int j = 0; j < k; ++ j)
            S[i] = (S[i] + P[i].d[j][j]) % MOD;
        for (int j = 1; j <= i; ++ j)
            C[i] = (C[i] - 1ll * C[j - 1] * S[i - j + 1] % MOD + MOD) % MOD;
        C[i] = 1ll * C[i] * powi(i, MOD - 2) % MOD;
    }
    pS.d[1] = 1;
    pS = powi(pS, st, l);


    for (int i = 0; i < k; ++ i)
        ans = ans + P[i] * pS.d[i];
    for (int i = 0; i < k; ++ i)
    {
        for (int j = 0; j < k - 1; ++ j)
            printf("%d ", ans.d[i][j]);
        printf("%d", ans.d[i][k - 1]);
        puts("");
    }
}
原文地址:https://www.cnblogs.com/AwD-/p/7066029.html