CF991D Bishwock
CF991D Bishwock
题目描述
给一个\(2\times n\)的网格,上面一些位置以及被覆盖上了。现在你有一种形状为L的小块,每个由三个小格组成,构成L型
现在问你,当前的网格最多还能摆多少小块(不能覆盖以及覆盖过的格子)
输入格式
两行两个字符串由\(X,0\)组成,\(X\)表示被覆盖了,\(0\)表示还没有
输出格式
一行 一个整数
样例输入
00X00X0XXX0
0XXX0X00X00
样例输出
4
对于\(100\)%的数据满足\(n\le 10^5\)
题目分析
大约一年前的模拟赛上似乎就出过这道题。(考试后证明我是对的......) 至于为什么要更这篇题解,因为今年差点没切(去年都切了.... 其实最后今年也没切,数组开小了)
个人想法就不说了,乱七八糟想了一堆,一个没搞出来。周围大佬们都切了,就先去看T2了(事实证明是正确的,如果T1切掉也就不会那么认真的去考虑T2)。
闲话少叙,步入正题。
首先我们观察一下数据范围....(然鹅并没有什么用) 突破口是在\(2\times n\)的矩阵,以及只有一种L型的块块。 所以,对于一个\(2\times 2\)的矩阵,合法情况是一定的。具体几种长什么样可以手画一下。
所以我们想到一种类似递推的更新方式。 预处理出来每列的状态:
\(f[i][1/2/3/4]\)分别表示每列的一种可能更新的状态。
\(f[i][1]\) \(XX\) \(f[i][2]\) \(0X\) \(f[i][3]\)$ X0 $ \(f[i][4]\) \(00\)
\(f[i][0]\)用来记录当前列的答案。
然后就是一堆特判。 注意对于每列更新完之后,\(f[i][2/3]\)这两种情况需要清零,而\(f[i-1][4]=1\)且\(f[i][4]=1\)时,\(f[i][4]\)只会被用到一次,所以可以拆成\(f[i][2/3] = 1\)以便接下来的操作。具体实现见代码。
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100020;
int f[N][5];
char str[3][N];
int main()
{
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
scanf("%s", str[1] + 1);
scanf("%s", str[2] + 1);
int n = strlen(str[1] + 1);
memset(f, -1, sizeof f);
for(int i = 1 ; i <= n ; i ++)
f[i][0] = 0;
for(int j = 1 ; j <= n ; j ++)
{
if(str[1][j] == '0' && str[2][j] == '0')
f[j][4] = 1;
else
if(str[1][j] == '0' && str[2][j] == 'X')
f[j][3] = 1;
else
if(str[1][j] == 'X' && str[2][j] == '0')
f[j][2] = 1;
else
if(str[1][j] == 'X' && str[2][j] == 'X')
f[j][1] = 1;
}
for(int i = 2 ; i <= n ; i ++)
{
if(f[i - 1][4] == 1 && f[i][4] == 1)
{
f[i][0] ++;
f[i][2] = 1;
f[i][3] = 1;
f[i][4] = 0;
}
else
if(f[i - 1][2] == 1 && f[i][4] == 1)
{
f[i][0] ++;
f[i][4] = 0;
}
else
if(f[i - 1][3] == 1 && f[i][4] == 1)
{
f[i][0] ++;
f[i][4] = 0;
}
else
if(f[i - 1][4] == 1 && f[i][3] == 1)
{
f[i][0] ++;
f[i][3] = 0;
}
else
if(f[i - 1][4] == 1 && f[i][2] == 1)
{
f[i][0] ++;
f[i][2] = 0;
}
}
int ans = 0;
for(int i = 1 ; i <= n ; i ++)
ans += f[i][0];
printf("%d", ans);
fclose(stdin);
fclose(stdout);
return 0;
}