kmjp's blog

競技プログラミング参加記です

yukicoder : No.1490 スライムと爆弾

これは典型かな…。
https://yukicoder.me/problems/no/1490

問題

H*Wのグリッドがあり、そこにN体のスライムがいる。
各スライムはグリッド上である矩形領域を占める。また、その体力が与えられる。

ここに、M個の爆弾を配置する。
各爆弾は、やはりグリッド上である矩形領域を占め、1マスあたりに与えるダメージが指定されている。

各スライムは、占める領域における爆弾のダメージの総和が、体力以上である場合に消滅する。
生き残るスライムの数を求めよ。

解法

累積和を何度も使う。
まず、爆弾に関し、累積和を使い、各マスに与えるダメージの総和を計算する。
次の、そのダメージを累積和を取ることで、矩形区間内の総ダメージをO(1)で計算できるようにする。
最後に各スライムの占める領域の総ダメージを求めよう。

int H,W,N,M;
int T[202020],U[202020],L[202020],R[202020],A[202020];
ll S[2020][2020];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>H>>W>>N>>M;
	FOR(i,N) {
		cin>>T[i]>>U[i]>>L[i]>>R[i]>>A[i];
	}
	FOR(i,M) {
		int b;
		cin>>y>>x>>b>>r;
		S[max(1,y-b)][max(1,x-b)]+=r;
		S[min(2010,y+b+1)][max(1,x-b)]-=r;
		S[max(1,y-b)][min(2010,x+b+1)]-=r;
		S[min(2010,y+b+1)][min(2010,x+b+1)]+=r;
	}
	FOR(y,H+2) FOR(x,W+2) {
		if(y) S[y][x]+=S[y-1][x];
		if(x) S[y][x]+=S[y][x-1];
		if(y&&x) S[y][x]-=S[y-1][x-1];
	}
	FOR(y,H+2) FOR(x,W+2) {
		if(y) S[y][x]+=S[y-1][x];
		if(x) S[y][x]+=S[y][x-1];
		if(y&&x) S[y][x]-=S[y-1][x-1];
	}
	
	int ret=0;
	FOR(i,N) {
		ll d=S[U[i]][R[i]]-S[T[i]-1][R[i]]-S[U[i]][L[i]-1]+S[T[i]-1][L[i]-1];
		if(d<A[i]) ret++;
	}
	cout<<ret<<endl;
	
}

まとめ

2次元累積和はいい加減ライブラリにすべきか…。