P5857 「SWTR-03」Matrix
一道不错的组合计数题。
题目大意
有一个 的 矩阵,初始时每个元素均为 。 有 次操作,每次选择第 行和第 列,将整行元素取反,再将整列元素取反。求 次操作后不同矩阵的种类数,答案对 取模。
大体思路
很容易发现,其实行与列的操作是互相独立的,因此本题相当于可重复地取反 行,并且可重复地取反 列。
由于最终某一行(列)有贡献,当且仅当这一行(列)被操作了奇数次,所以我们枚举有 行 列被操作了奇数次,其中 ,,并且 的奇偶性与 相同。那么,答案即为
但是,我们会发现样例中 的情况便出现了问题。我们思考某一个元素变成 的条件。
如果用 表示某一行 被操作偶数次或奇数次,记为 ,那么 。此时,如果将代表每一行列的 变量 取反,可以证明 ,因此这种情况下整个矩阵是相同的。
我们研究何时这种情况会出现。基于行列情况等价,我们讨论行的情况。由于 的奇偶性与 相同,即 ,同时取反后 ,两式相加得 。也就是说, 均为偶数。
同时,重复部分需要满足 ,所以 , 同理。我们记这一部分的答案为
由于重复部分在 中均被计算两次,最终答案减去重复部分的一半即可,即 。
由于 为质数,计算 以及使用除法时,利用费马小定理 , 计算逆元即可。由于 同阶,总的时间复杂度为 ,其中 来自于预处理阶乘逆元时快速幂的复杂度。
完整代码
#include <bits/stdc++.h> using namespace std; #define rep(ii,aa,bb) for(re ll ii = aa; ii <= bb; ii++) #define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--) typedef long long ll; typedef unsigned long long ull; typedef double db; typedef pair<int, int> PII; const int maxn = 2e5 + 5; const ll mod = 998244353; namespace IO_ReadWrite { #define re register #define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++) char _buf[1<<21], *p1 = _buf, *p2 = _buf; template <typename T> inline void read(T &x){ x = 0; re T f=1; re char c = gg; while(c > 57 || c < 48){if(c == '-') f = -1;c = gg;} while(c >= 48 &&c <= 57){x = (x<<1) + (x<<3) + (c^48);c = gg;} x *= f;return; } inline void ReadChar(char &c){ c = gg; while(!isalpha(c)) c = gg; } template <typename T> inline void write(T x){ if(x < 0) putchar('-'), x = -x; if(x > 9) write(x/10); putchar('0' + x % 10); } template <typename T> inline void writeln(T x){write(x); putchar('\n');} } using namespace IO_ReadWrite; ll n, m, k, T, inv[maxn], fac[maxn]; inline ll Pow(ll a, ll b) { ll res = 1; while(b) { if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1; } return res % mod; } inline void init() { int N = 2e5; fac[0] = inv[0] = 1; rep(i, 1, N) { fac[i] = (i * fac[i - 1]) % mod; inv[i] = Pow(fac[i], mod - 2); } } inline ll C(ll n, ll m) { ll res = fac[n]; return (((res * inv[m]) % mod) * inv[n - m]) % mod; } inline void solve() { read(n); read(m); read(k); ll c = (k & 1); ll sI = 0, sJ = 0; for(ll i = c; i <= min(n, k); i += 2) (sI += C(n, i)) %= mod; for(ll j = c; j <= min(m, k); j += 2) (sJ += C(m, j)) %= mod; ll ans = (sI * sJ) % mod; if(!(n & 1) && !(m & 1)) { ll dI = 0, dJ = 0; for(ll i = max(n - k, 0ll); i <= min(n, k); i += 2) (dI += C(n, i)) %= mod; for(ll j = max(m - k, 0ll); j <= min(m, k); j += 2) (dJ += C(m, j)) %= mod; ll dlt = ((dI * dJ % mod) * inv[2]) % mod; ans = (ans - dlt + mod) % mod; } writeln(ans); } int main () { init(); read(T); while(T --) solve(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】