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}\) 即可。所以答案为:

\[\begin{aligned} &\frac{1}{3^{n+m}}\sum_{a_1,a_2,\ldots,a_n\in\{1,\omega,\omega^2\}}\sum_{b_1,b_2,\ldots,b_m\in\{1,\omega,\omega^2\}}\prod_{i=1}^{n}\prod_{j=1}^{m}{\left[\sum_{t=0}^{k}{(a_ib_j)^t}\right]}\\ =&\frac{1}{3^{n+m}}\sum_{a_1,a_2,\ldots,a_n\in\{1,\omega,\omega^2\}}\sum_{b_1,b_2,\ldots,b_m\in\{1,\omega,\omega^2\}}\prod_{j=1}^{m}\prod_{i=1}^{n}{\left[\sum_{t=0}^{k}{(a_ib_j)^t}\right]}\\ =&\frac{1}{3^{n+m}}\sum_{a_1,a_2,\ldots,a_n\in\{1,\omega,\omega^2\}}\left\{\sum_{c=0}^{2}\prod_{i=1}^{n}{\left[\sum_{t=0}^{k}{(a_i\omega^c)^t}\right]}\right\}^m\\ =&\frac{1}{3^{n+m}}\sum_{r_0+r_1+r_2=n}\binom{n}{r_0,r_1,r_2}\left\{\sum_{c=0}^{2}\prod_{d=0}^{2}{\left[\sum_{t=0}^{k}{(\omega^d\omega^c)^t}\right]}\right\}^m\\ =&\frac{1}{3^{n+m}}\sum_{r_0+r_1+r_2=n}\binom{n}{r_0,r_1,r_2}\left\{\sum_{c=0}^{2}\prod_{d=0}^{2}{\left[\sum_{t=0}^{k}{\omega^{(c+d)t}}\right]}\right\}^m \end{aligned} \]

由于 \(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;
}
posted @ 2025-10-18 16:13  下蛋爷  阅读(35)  评论(0)    收藏  举报