【Codeforces Round #693 (Div. 3) F】New Year's Puzzle

题目链接

链接

翻译

给你一个 \(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;
}

posted @ 2021-01-13 21:13  AWCXV  阅读(160)  评论(4编辑  收藏  举报