【Codeforces Round #693 (Div. 3) F】New Year's Puzzle
阿新 • • 發佈:2021-02-07
題目連結
翻譯
給你一個 \(2*n\) 的方格,讓你用 \(1*2\) 的骨牌,橫著或者豎著放,鋪滿整個方格。
其中有一些被黑色方塊阻擋,不能放骨牌。問你可不可行。
題解
首先考慮 整個方格 第一列,如果兩行都是空的。
那麼考慮第二列的幾種情況:
- 第二列也是空的,那麼第一列放豎的沒問題。
- 第二列有一個方格被堵住了,那麼第一列只能豎著放了,不然鋪不滿(注意這是第一列,它之前沒有列了)
- 第二列有兩個方格都被堵住了,那麼第一列也同樣是豎著放。
綜上所述,第一列如果兩行都是空的,那麼就豎著放一個就行。
這樣就可以不斷地 \(Reduce\)
當然,如果第一列兩行都被堵住了,那麼同樣的也可以縮減問題,因為這一列不用放骨牌...
這樣,我們的問題的第一列就總是隻有一個方格被堵住的情況了。
這個時候我們只能放一個橫的骨牌,會突出來一部分。而且,如果它的右邊仍然是兩行都是空著的情況,那麼又得繼續橫著放一個。
直到遇到某個位置也恰好只有一行被堵住,則需要判斷一下能不能剛好填滿兩行。所以中間的大概 \(n-m\) 個空格可以直接跳過。
這裡能否填滿兩行的情況需要根據前後兩個 只有一行被堵住 的列的座標差的奇偶性來判斷,為奇數,則被堵住的行號應該相同。否則,應該不同。
程式碼
#include <bits/stdc++.h> #define LL long long using namespace std; const int N = 2e5; const LL MOD = 1e9 + 7; const int K = 5000; int n, m; map<int, int> dic; int main() { #ifdef LOCAL_DEFINE freopen("in.txt", "r", stdin); #endif ios::sync_with_stdio(0), cin.tie(0); int T; cin >> T; while (T--) { dic.clear(); cin >> n >> m; for (int i = 1; i <= m; i++) { int r, c; cin >> r >> c; dic[c] |= (1 << (r - 1)); } //reduce map<int,int>::iterator it = dic.begin(); while (it != dic.end()) { pair<int, int> temp = *it; if (temp.second == 0 || temp.second == 3) { m--; it++; continue; } else { break; } } if (it == dic.end()) { cout << "YES" << endl; continue; } //it.second == 2 || it.second == 1 pair<int,int> pre = (*it); it++; bool ok = true; while (it != dic.end()) { if (pre.second == 0 || pre.second == 3) { pre = (*it); it++; continue; } int temp = (*it).second; int delta = (*it).first - pre.first; if (temp == 0) { if (delta%2 == 0) { pre.second = 3 - pre.second; } pre.first = (*it).first; } else if (temp == 1 || temp == 2){ if (delta % 2 == 0) { if (temp != pre.second) { } else { ok = false; break; } } else { if (temp == pre.second) { } else { ok = false; break; } } pre = *it; pre.second = 3; it++; } else { //temp==3 if (pre.second != 0 && pre.second != 3) { ok = false; break; } it++; } } if (!ok || pre.second == 1 || pre.second == 2) { cout << "NO" << endl; } else { cout << "YES" << endl; } } return 0; }