210818构造模拟赛挂分记

概述

今天是构造,题似乎不是很难,然而我挂的很惨。

期望:\(100+30+60+100=290\)​,实际 \(0+20+0+5=25\)​。大家都挂的很惨,于是我 RK13/23。。。

前言

实际上我从来没有做过构造题,唯一的是前一天听同学口胡的一道 CF \(1000+\)​ 分的题,于是今天十分没底。

赛时

看到保证 T1 是最简单的题,我立马定好策略:切掉 T1 再说。(T1:CF1439A2

于是开始想,大概想了十分钟吧,思路就已经成型了:枚举每个 \(2\times 2\)​​ 正方形左上角的点,从第一行扫到倒数第三行,扫的时候保证该行所有 \(1\) 都已经变成 \(0\),其他随意。接着横着扫倒数第二行,一直扫到倒数第三列。这个时候除了右下角 \(2\times2\) 的四个数,所有数都已经变为 \(0\) 了。而对于最后四个数,可能的剩余未熄灭灯数只有 \(5\)​​ 种。直接用打表/分类讨论之类的方法搞出来就行。

Code
#include
#define mm(x) memset(x, 0, sizeof(x))
using namespace std;
int T, n, m, a[110][110];
struct node
{
	int x, y;
};
vector p;
void upd(int x, int y, int &q)
{
	p.push_back((node){x, y});
	a[x][y] = a[x][y] == 1 ? 0 : 1;
	q--;
}
int b[4][4];	
void solve_1()
{	
	int cnt = 3;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			if (a[n - i][m - j] == 1)
				upd(n - i, m - j, cnt);
}
void solve_2()
{
	mm(b);
	int cnt = 3;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			if (a[n - i][m - j] == 0)
				upd(n - i, m - j, cnt), b[i][j] = 1;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			if (!b[i][j])
				upd(n - i, m - j, cnt);
	solve_1();
}
void solve_3()
{
	mm(b);
	int cnt = 3;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			if (a[n - i][m - j] == 1)
				upd(n - i, m - j, cnt), b[i][j] = 1;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			if (!b[i][j])
				upd(n - i, m - j, cnt), b[i][j] = 1;
	solve_2();
}
void solve_0()
{
	int cnt = 3;
	upd(n, m, cnt);
	upd(n, m - 1, cnt);
	upd(n - 1, m, cnt);
	solve_3();
}
void out_put()
{
	cout << p.size() / 3;
	for (int i = 0; i < p.size(); i++)
	{
		if (i % 3 == 0)
			cout << "\n";
		cout << p[i].x << " " << p[i].y << " ";
	}
	cout << "\n";
}
int main()
{
	freopen("bulb.in", "r", stdin);
	freopen("bulb.out", "w", stdout);
	ios::sync_with_stdio(false);
	cin >> T;
	while (T--)
	{
		cin >> n >> m;
		p.clear();
		char ch;
		int ans = 0;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				cin >> ch, a[i][j] = ch == '0' ? 0 : 1;
		for (int i = 1; i < n - 1; i++)
			for (int j = 1; j < m; j++)
			{
				int cnt = 3;
				if (a[i][j] == 1)
					upd(i, j, cnt);
				if (a[i][j + 1] == 1)
					upd(i, j + 1, cnt);
				if (cnt == 3)
					continue;
				if (cnt)
					upd(i + 1, j, cnt);
				if (cnt)
					upd(i + 1, j + 1, cnt);
			}
		for (int j = 1; j < m - 1; j++)
		{
			int cnt = 3;
			if (a[n - 1][j] == 1)
				upd(n - 1, j, cnt);
			if (a[n][j] == 1)
				upd(n, j, cnt);
			if (cnt == 3)
				continue;
			if (cnt)
				upd(n - 1, j + 1, cnt);
			if (cnt)
				upd(n, j + 1, cnt);
		}
		int tot = 0;
		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 2; j++)
			{
				tot += a[n - i][m - j];
			}
		tot = 4 - tot;
		if (tot == 0)
			solve_0();
		else if (tot == 1)
			solve_1();
		else if (tot == 2)
			solve_2();
		else if (tot == 3)
			solve_3();
		out_put();
	}
	return 0;
}

写完 T1,按传统规矩自然是 DEBUG 了好久,确定无误之后已经过去一个半小时了,感觉自己得了 \(100\) 分,一阵狂喜,赶快开下面的题。

接着看后面的题,决定先打暴力。

首先打了个 T3 的 \(60\) 分暴力,一阵狂喜,然后去写 T4,分析了一下发现我似乎能切。于是开始写,但是调到心态爆炸,于是在剩余 \(20\text{min}\)​​ 的时候勉强调完了,急的一笔,快速打了个暴力,希望能得 \(30\) 分。不过也没测试,草草收场了。

然后快结束的时候有人告诉我 T1 的文件名写错了,我:???

结果还真写错了,我连忙改文件名和 freopen 里的文件名。

时间到了,我一看,我 freopen 里的文件名没改上,我:???发生什么事了???

行吧, \(100\) 分没了。

赛后

我一看分数就傻眼了。

再一看:T3 File Error:“未找到选手输出文件”

哦,仔细一看,我把一个 freopen 的文件名写错了,好家伙,这又少了 \(60\) 分。

T4 果然挂了,不出所料,不过我和 Solution 的思路是差不多的,但是实现似乎有点问题。

又在 OJ 上交了一发,好家伙,T1 直接 AC 了,T3 \(60\) 分了。

忽然意识到,我因为 freopen 痛失了 \(100+60=160\) 分。太伤了,加上这些分我似乎能进 Rank 5。

题目都不是很难,T2 其实是个分类讨论题,感觉再来点时间也能想出来,倒是 T3 似乎思维难度最大,有点类似染色(

总结

狂喜把自己狂喜没了,这次在做题上还算是比较完美的,不过下一次必须认真比对文件名之后(或者直接复制)再去搞下一道题。

这次太着急了,所以出了一堆错误。

T1 明明几分钟就想出来正解了,结果后面又否定自己,最后又发现自己是对的,也浪费了大量时间。

代码实现的时候也浪费了时间。

只能说码力还是不够,正解和暴力都写得太慢了,结果没有时间支持我深入思考每道题,相信随着刷题数的增多我这个能力能增强的。

posted @ 2021-08-18 22:44  _slb  阅读(39)  评论(0编辑  收藏  举报