1. 程式人生 > 其它 >CF1644D Cross Coloring 題解

CF1644D Cross Coloring 題解

Tag

計數。

Preface

考場上因為這題打錯了一個地方然後擺爛了,感覺後面兩題本來是可以做的啊……

Description

給一個 \(n\times m\) 的棋盤塗上 \([1, k]\) 的顏色,塗色的規則是,選擇一個 \((x,y)\) 座標,使其 \(x\) 行和 \(y\) 列全都塗成一個顏色,給定 \(q\) 個塗色位置 \((x,y)\),求最後棋盤有多少種情況,對 \(998244353\) 取模。

\(\texttt{data range:} n,m,k,q \leq 2\times 10^5\).

Solution

直接做是困難的,不妨反過來思考,我們優先塗最後需要塗色的位置,因為這個位置會把所有其他的顏色覆蓋住,如果說從後往前塗,某一個位置其其他位置都被覆蓋了,那麼這個位子就沒有意義,所以不計入貢獻。

於是我們記錄橫座標和縱座標哪些位置被塗過,但是注意我們還需要記錄橫行和縱列有多少個位置被塗過,因為如果說下圖這樣一種塗色的話,那麼也是沒有意義的。

. . .

. . .

* * *

其中 * 代表已經被塗過,可以發現不論我們選擇剩下的哪一個位置塗入都不會影響棋盤的狀態,所以我們需要特判這個地方。(我考場上就是這裡寫錯了然後就擺爛了)

Code

const int N = 2e5 + 10;
const int mod = 998244353;

int n, m, k, q, cntx, cnty;
int X[N], Y[N];
bool visx[N], visy[N];

inline void work() {
  cin >> n >> m >> k >> q;
  ll ans = 1;
  for(int i = 1; i <= q; i++) 
    cin >> X[i] >> Y[i];
  for(int i = q; i; i--) {
    bool flag = false;
    flag |= (visx[X[i]] && visy[Y[i]]);
    flag |= (visx[X[i]] && cntx == n);
    flag |= (visy[Y[i]] && cnty == m);
    if(!visx[X[i]]) visx[X[i]] = true, cntx++;
    if(!visy[Y[i]]) visy[Y[i]] = true, cnty++;
    if(!flag) ans = ans * k % mod;
  }
  for(int i = q; i; i--) 
    visx[X[i]] = false, visy[Y[i]] = false;
  cntx = 0, cnty = 0;
  cout << ans << '\n';
  return ;
}

inline void solve() {
  cin.sync_with_stdio(false);
  int t;
  cin >> t;
  while(t--) 
    work();
  return ;
}