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_tconst 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 ORZXKRfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifstd::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;
}