洛谷 P5542 Painting the barn(二维差分 模板)

题目大意:

小明对着墙壁画矩形,问小明画的矩形里面重叠k次的区域面积是多大。

解题思路:

首先,我们可以想到对画的一片区域进行+1操作,最后扫描一遍画的区域,若某个点的和为k我们就记录下来。

首先,我们可以试一下naive的+1,发现复杂多太高。这时候引入一个新结构叫做二维差分,二维差分再配合二维前缀和就可以达到O(n^2)的更新一片区域。关于二维差分,这里有一个解释:

https://www.cnblogs.com/LMCC1108/p/10753451.html

二维差分的公式是:假若我们想对(x1,y1)到(x2,y2)的区域进行+val操作。我们可以:

\\gra[x1][y1]+=val\\ gra[x2][y2+1]-=val\\ gra[x2+1][y1]]-=val\\ gra[x2+1][y2+1]+=val\\

 

其中gra是棋盘。为什么可以这样呢?简要来说,就是通过引入+val 和-val的标签后,在计算二位前缀和时可以达到只对某个区域+val的操作。大家可以试着动手算算。二维前缀和的公式是:

gra[x][y-1]+gra[x-1][y]-gra[x-1][y-1]+gra[x][y]

 

但注意在边界时,有些数组越界的项我们是需要去掉的。

AC代码:

#include 
using namespace std;
const int MAXN=1e3+10;
int main(){
	int n,k;cin>>n>>k;
	vector> chess(MAXN,vector(MAXN,0));
	for(int i=0;i>x1>>y1>>x2>>y2;
		x2-=1;y2-=1;
		chess[x1][y1]+=1;
		chess[x1][y2+1]-=1;
		chess[x2+1][y1]-=1;
		chess[x2+1][y2+1]+=1;
	}
	int ans=0;
	for(int x=0;x=1)ret+=chess[x-1][y];
			if(y>=1)ret+=chess[x][y-1];
			if(x>=1 && y>=1)ret-=chess[x-1][y-1];
			chess[x][y]=ret;
			if(ret==k)ans++;
		}
	cout<

你可能感兴趣的:(DP,洛谷)