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);
}
}