DTOJ 5093 淘淘种地 题解

题面

题目链接

题解

这个是CSP前最后一场测试的 T2,打的不是很好,没有想到这题正解,但是这题暴力分很多ww

二进制拆位的思想要有((

30分

暴力模拟 \(O(nmT)\)

70分

满足 \(1 \leq a[i][j], k[i] \leq 2\)

对每种肥料做一遍前缀和,得出每个点被哪些种类覆盖. \(O(T+nm)\). 因为只有两种所以很可做.

100分

部分分启发我们二进制拆位(虽然测试的时候没启发到我)

总之拆位.

对每一位的 \(0\)\(1\) 分别做一遍前缀和,最后如果与 \(a[i][j]\) 不同的位上有肥料,他就安详地去世了.

效率就是\(O((T+nm)\log nm)\)

然后你会发现你 RE MLE

实现要注意:

不要用 vector,空间真的很容易炸

把二维数组压成一位数组

把枚举位数的循环扔外面,数组可以少一位

然后你就快乐 AC

(当然这题有别的做法,什么树状数组之类的

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5;
int n,m,T;
int a[N<<2],d[2][N<<2],xa[N],ya[N],xb[N],yb[N],k[N],ans[N<<2];
inline int f(int i, int j) { return i*(m+3)+j; }
int main()
{
	scanf("%d%d%d",&n,&m,&T);
	for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&a[f(i,j)]);
	for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) ans[f(i,j)]=1;
	for(int i=1; i<=T; i++) 	scanf("%d%d%d%d%d",&xa[i],&ya[i],&xb[i],&yb[i],&k[i]);
	for(int c=0; c<22; c++)
	{	
		for(int t=0; t<=1; t++) for(int i=0; i<=n+1; i++) for(int j=0; j<=m+1; j++) d[t][f(i,j)]=0;
		for(int i=1; i<=T; i++)
		{
			d[(k[i]>>c)&1][f(xa[i],ya[i])]++;
			d[(k[i]>>c)&1][f(xb[i]+1,yb[i]+1)]++;
			d[(k[i]>>c)&1][f(xa[i],yb[i]+1)]--;
			d[(k[i]>>c)&1][f(xb[i]+1,ya[i])]--;
		}
		for(int t=0; t<=1; t++) for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
			d[t][f(i,j)]+=d[t][f(i,j-1)]+d[t][f(i-1,j)]-d[t][f(i-1,j-1)];
		for(int i=1; i<=n; i++)
			for(int j=1; j<=m; j++)
			{
				int t=(a[f(i,j)]>>c)&1;
				if(d[t^1][f(i,j)]>0) ans[f(i,j)]=0;
			}
	}
	int cnt=0;
	for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(!ans[f(i,j)]) cnt++;
	printf("%d\n",cnt);
	return 0;
}
posted @ 2022-11-13 19:19  copper_carbonate  阅读(24)  评论(0编辑  收藏  举报