NOI模拟题4 Problem B: 小狐狸(fox)

Solution

考虑分开统计朝向每一个方向的所有狐狸对答案的贡献. 比如说以向右为例, 我们用箭标表示每一只狐狸的方向, 用\('\)表示当前一步移动之前的每一只狐狸的位置.

\[\begin{aligned} \sum_{d_i = \rightarrow} x_iy_i &= \left( \sum_{d_i = \rightarrow} S \times (x_i' + 1)y_i' \right) + \left( \sum_{d_i = \uparrow} L \times x_i'y_i' \right) + \left( \sum_{d_i = \downarrow} R \times x_i' y_i' \right) \\ &= \left( \sum_{d_i = \rightarrow} S \times x_i'y_i' \right) + \left( \sum_{d_i = \rightarrow} S \times y_i' \right) + \left( \sum_{d_i = \uparrow} L \times x_i'y_i' \right) + \left( \sum_{d_i = \downarrow} R \times x_i' y_i' \right) \end{aligned} \]

这样一来, 我们发现只需要统计朝向每个方向的狐狸的\(\sum x\), \(\sum y\), \(\sum xy\)即可. 考虑怎么更新这几个值: 我们再多记录一个\(sum\)表示朝向每个方向的狐狸的数量.

然后我们就得到了\(4 \times 4 = 16\)个需要维护的变量.

我们建立一个\(16 \times 16\)的矩阵, 用于使得这些变量相互转移.

矩阵快速幂.

构建这个矩阵还是挺麻烦的.

总结: DP的优化除了常见的斜率/优先队列外, 不要忘了还有矩乘可用.

#include <cstdio>
#include <cstring>

const long long mv[4][2] = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
const long long MOD = 1e9 + 7;
struct matrix
{
    long long a[16][16];
    inline void build(long long S, long long L, long long R)
    {
        memset(a, 0, sizeof(a));
        for (long long i = 0; i < 4; ++ i)
        {
            for (long long j = 0; j < 4; ++ j)
                a[4 * i | j][4 * i | j] += S,
                a[4 * i | j][4 * ((i - 1 + 4) % 4) | j] += R,
                a[4 * i | j][4 * ((i + 1 + 4) % 4) | j] += L;
            for (long long j = 0; j < 2; ++ j)
                a[4 * i | j][4 * i | 2] = (a[4 * i | j][4 * i | 2] + S * mv[i][j] + MOD) % MOD,
                a[4 * i | 3][4 * i | j] = (a[4 * i | 3][4 * i | j] + S * mv[i][! j] + MOD) % MOD;
        }
/*        for (long long i = 0; i < 16; ++ i)
        {
            for(long long j = 0; j < 16; ++ j) prlong longf("%d ", a[i][j]);
            puts("");
        } */
    }
    inline matrix friend operator *(matrix a, matrix b)
    {
        matrix res; memset(res.a, 0, sizeof res.a);
        for (long long i = 0; i < 16; ++ i) for (long long j = 0; j < 16; ++ j) for (long long k = 0; k < 16; ++ k)
            res.a[i][j] = (res.a[i][j] + a.a[i][k] * b.a[k][j] % MOD) % MOD;
        return res;
    }
}trans, a;
inline matrix power(long long x)
{
    matrix res; memset(res.a, 0, sizeof res.a);
    for (long long i = 0; i < 16; ++ i) res.a[i][i] = 1;
    for (; x; trans = trans * trans, x >>= 1)
        if (x & 1) res = res * trans;
    return res;
}
int main()
{

#ifndef ONLINE_JUDGE

    freopen("fox.in", "r", stdin);
    freopen("fox.out", "w", stdout);

#endif

    long long T; scanf("%d", &T);
    for(long long cs = 0; cs < T; ++ cs)
    {
        long long t, S, L, R; scanf("%lld%lld%lld%lld", &t, &S, &L, &R);
        trans.build(S, L, R);
        matrix res = power(t);
        long long ans = 0;
        for (long long i = 3; i < 16; i += 4) ans = (ans + res.a[i][2]) % MOD;
        printf("%d\n", ans);
    }
}

posted @ 2017-09-24 20:49  Zeonfai  阅读(183)  评论(0编辑  收藏  举报