210818构造模拟赛挂分记
Posted Touma_Kazusa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 明明几分钟就想出来正解了,结果后面又否定自己,最后又发现自己是对的,也浪费了大量时间。
代码实现的时候也浪费了时间。
只能说码力还是不够,正解和暴力都写得太慢了,结果没有时间支持我深入思考每道题,相信随着刷题数的增多我这个能力能增强的。
以上是关于210818构造模拟赛挂分记的主要内容,如果未能解决你的问题,请参考以下文章