zoukankan      html  css  js  c++  java
  • NOI模拟题4 Problem B: 小狐狸(fox)

    Solution

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

    [egin{aligned} sum_{d_i = ightarrow} x_iy_i &= left( sum_{d_i = ightarrow} S imes (x_i' + 1)y_i' ight) + left( sum_{d_i = uparrow} L imes x_i'y_i' ight) + left( sum_{d_i = downarrow} R imes x_i' y_i' ight) \ &= left( sum_{d_i = ightarrow} S imes x_i'y_i' ight) + left( sum_{d_i = ightarrow} S imes y_i' ight) + left( sum_{d_i = uparrow} L imes x_i'y_i' ight) + left( sum_{d_i = downarrow} R imes x_i' y_i' ight) end{aligned} ]

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

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

    我们建立一个(16 imes 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
    ", ans);
        }
    }
    
    
  • 相关阅读:
    Happy New Year
    CF1450G
    理希的NOI2020退役记
    luoguP4859 已经没有什么好害怕的了(二项式反演)
    知识点简单总结——二项式反演
    bzoj4671 异或图(斯特林反演,线性基)
    知识点简单总结——斯特林数、斯特林反演
    uoj450 【集训队作业2018】复读机(生成函数,单位根反演)
    有标号DAG计数(生成函数)
    知识点简单总结——单位根反演
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7588557.html
Copyright © 2011-2022 走看看