QOJ #14426. Grid Problem 题解
Description
给定一个大小为 \(n\times m\) 的初始全为 \(0\) 的循环矩阵,每次可以给矩阵做 \(\pm\begin{bmatrix}2&1\\1& 2\end{bmatrix}\) 或者 \(\pm\begin{bmatrix}2&5&2\\5&5&5\\2&5&2\end{bmatrix}\),问最终所有元素都在 \([0,k]\) 的最终状态数量。
对 \(10^9+9\) 取模。
\(3\leq n,m\leq 10^3,1\leq k\leq 10^9\)。
Solution
首先容易猜到一个最终状态合法,当且仅当所有行内元素的和以及所有列内元素的和都是 \(3\) 的倍数。
注意到我们是很难直接刻画每行每列是否都是 \(3\) 的倍数这个限制,考虑利用这篇文章中的思想,用单位根刻画这个问题。
具体地,定义一个函数三次单位根为 \(\omega\),\(\displaystyle F(a_1,a_2,\ldots,a_n,b_1,b_2,\ldots,b_m)=\prod_{i=1}^{n}\prod_{j=1}^{m}{\left[\sum_{t=0}^{k}{(a_ib_j)^t}\right]}\)。
然后对于所有满足 \(a_i,b_j\in\{1,\omega,\omega^2\}\) 的 \(a\) 和 \(b\),求出它们 \(F\) 函数的和。
对于一组可能的 \(t\),如果存在一个 \(a_i\),这一行或者这一列的系数贡献之和不是 \(3\) 的倍数,那么带入 \(a_i=1,\omega,\omega^2\) 后,这一行对这组 \(t\) 的方案的贡献为 \(1+\omega+\omega^2=0\),\(b_j\) 同理。也就是说不合法的情况被消掉了!
而如果所有 \(a_i,b_j\) 都是 \(3\) 的倍数,对总和的贡献为 \(3^{n+m}\),最后除掉 \(3^{n+m}\) 即可。所以答案为:
由于 \(10^9+8\) 是 \(3\) 的倍数,所以一定能找到 \(\bmod 10^9+9\) 意义下的单位根。找到单位根后暴力枚举 \(r_0,r_1,c,d\) 即可。
时间复杂度:\(O(n^2\log m)\)。
Code
#include <bits/stdc++.h>
#define int int64_t
const int kMaxN = 1e3 + 5, kMod = 1e9 + 9;
int n, m, k, w[3];
int fac[kMaxN], ifac[kMaxN], s[3], pw[3][kMaxN];
int qpow(int bs, int64_t idx = kMod - 2) {
int ret = 1;
for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod)
if (idx & 1)
ret = (int64_t)ret * bs % kMod;
return ret;
}
inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }
void prework(int n = 1e3) {
fac[0] = ifac[0] = 1;
for (int i = 1; i <= n; ++i) {
fac[i] = 1ll * fac[i - 1] * i % kMod;
ifac[i] = qpow(fac[i]);
}
}
void dickdreamer() {
std::cin >> n >> m >> k;
prework();
w[0] = 1, w[1] = qpow(5, (kMod - 1) / 3), w[2] = qpow(5, (kMod - 1) / 3 * 2);
s[0] = (k + 1) % kMod;
for (int i = 0; i <= k % 3; ++i) {
inc(s[1], w[i]);
inc(s[2], w[i * 2 % 3]);
}
for (int o = 0; o < 3; ++o) {
pw[o][0] = 1;
for (int i = 1; i <= n; ++i) pw[o][i] = 1ll * pw[o][i - 1] * s[o] % kMod;
}
// std::cerr << w[2] << ' ' << add(w[0], add(w[1], w[2])) << '\n';
int ans = 0;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= n - i; ++j) {
int k = n - i - j;
int coef = 1ll * fac[n] * ifac[i] % kMod * ifac[j] % kMod * ifac[k] % kMod;
int val = 0;
for (int c = 0; c < 3; ++c) {
int mul = 1;
for (int d = 0; d < 3; ++d) mul = 1ll * mul * pw[(c + d) % 3][(d == 0 ? i : (d == 1 ? j : k))] % kMod;
inc(val, mul);
}
inc(ans, 1ll * coef * qpow(val, m) % kMod);
}
}
std::cout << 1ll * ans * qpow(qpow(3, n + m)) % kMod << '\n';
}
int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

浙公网安备 33010602011771号