kmjp's blog

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

yukicoder : No.655 E869120 and Good Triangles

ややこしいけど何とか。
https://yukicoder.me/problems/no/655

問題

整数Nが与えられたとき、以下の正三角形状に頂点が並んだ無向グラフを考える。

頂点がN段あり、上からi段目にはi個の頂点が並んでいる。上からx段、左からy列目の頂点を(x,y)と表す。
各頂点は、同じ段の左右隣り、および上下段の左右近傍頂点2個ずつ計最大6個の点に隣接しており、その間で辺が張られている。

ここでいくつかの頂点が指定される。
この状態で、各頂点(x,y)のスコアA(x,y)は、最寄りの指定頂点までの最短距離で定義される。

ここで、正三角形状の区間内の頂点群を選んだ時、スコアの総和がP以上となるのは何通りか。

解法

A(x,y)はまずダイクストラの要領で求めればO(N^2)で解ける。
問題は数え上げパートで、頂点群の選び方はO(N^3)通りあるので1つずつ数えていくと間に合わない。

そこで累積和と尺取り法を用いる。
下辺の両端を決めれば正三角形の形状が定まり、内部のスコアの総和も求まる。
よって下辺の両端を尺取り法しよう。

下辺の段は総当たりする。
今x段目を見ていくとき、下辺の左端をL、右端をRとする。
するとこの2点を可変の両端とする正三角形は(x,L)(x,R)(x-(R-L),L)で囲まれた領域となる。

Lを1ずつずらしたとき、尺取り法の要領で正三角形内のスコアの総和がPを超えない範囲でRを大きくしよう。この手順は均しO(N^2)で解ける。
そうすると、逆に正三角形の左下を(x,L)としたとき、右下を(x,R+1)~(x,x)にしたときP以上になる。

問題はL,Rをずらしたときの正三角形内のスコアの変化量である。
(x,L)(x,R)(x-(R-L),L)で囲まれた領域において、Lをインクリメントすると(x,L)-(x-(R-L),L)の頂点が正三角形から外になる。
またRをインクリメントすると(x,R+1)-(x-(R+1-L),L)の頂点が正三角形に入る。
よって左下-右上方向および右下-左上方向の2通り1次元累積和を事前に取っておけば、スコアの変化量がO(1)で評価できる。
2次元累積和で頑張ってもO(1)で求められるね。

int N,K;
ll P;
int D[4040][4040];
int L[4040][4040];
int R[4040][4040];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>K>>P;
	
	FOR(x,N) FOR(y,N) D[x][y]=101010;
	queue<pair<int,int>> Q;
	FOR(i,K) {
		cin>>x>>y;
		x--,y--;
		D[x][y]=0;
		Q.push({x,y});
	}
	
	while(Q.size()) {
		x=Q.front().first;
		y=Q.front().second;
		Q.pop();
		
		int dx[6]={-1,0,-1,1,0,1};
		int dy[6]={-1,-1,0,0,1,1};
		FOR(i,6) {
			int tx=x+dx[i];
			int ty=y+dy[i];
			if(tx<0 || tx>=N || ty<0 || ty>tx) continue;
			if(D[tx][ty]>D[x][y]+1) {
				D[tx][ty]=D[x][y]+1;
				Q.push({tx,ty});
			}
		}
	}
	
	for(x=N-1;x>=0;x--) {
		FOR(y,x+1) {
			L[x][y]=D[x][y]+L[x+1][y];
			R[x][y]=D[x][y]+R[x+1][y+1];
		}
	}
	
	ll ret=0;
	for(x=N-1;x>=0;x--) {
		ll S=0;
		for(int LL=0,RR=-1;LL<=x;LL++) {
			
			if(RR<=LL) RR=LL, S=0;
			while(RR<=x&&S+(R[x-(RR-LL)][LL]-R[x+1][RR+1])<P) {
				S+=(R[x-(RR-LL)][LL]-R[x+1][RR+1]);
				RR++;
			}
			ret+=x+1-RR;
			S-=(L[x-(RR-1-LL)][LL]-L[x+1][LL]);
		}
	}
	cout<<ret<<endl;
	
}

まとめ

2次元以上の累積和は頭が混乱するので、無理やり1次元の累積和を駆使するの好き。