kmjp's blog

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

yukicoder : No.274 The Wall

3問とも急ぎすぎて細かいミスを重ねてしまい、回答が遅れてしまった。
http://yukicoder.me/problems/658

問題

大きさ1x1の正方形ブロックを横にM個連結した大きさ1xMのブロックがある。
各1x1ブロックは基本白色だが、左からL[i]~R[i]番目の1x1ブロックはピンク色である。
これらの1xMブロックは180度回転することが可能である。

このような1xMブロックがN個与えられるので、縦に綺麗に積んでいきたい。
各1xMブロックは180度回転しても良い場合、各列ピンクである1x1ブロックが1行以下であるように並べられるか答えよ。

解法

向きの確定していない1xMブロックのうち、ピンク色の1x1ブロックが一番左側に来るような1xMブロックを貪欲に選んで行けばよい。
その際、すでに向きが確定してしまった1xMブロックと同じ列にピンク色が共に来てしまう場合、未確定なブロックは180度回転させる。
180度回転させても、すでに向きが確定してしまった1xMブロックと同じ列にピンク色が共に来てしまう場合、条件は満たせない。

以下のコードはO(N^2)だけど、恐らくO(N*logN)でも通ると思う。

int N,M;
int L[2020],R[2020];
int vis[2020];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>M;
	FOR(i,N) cin>>L[i]>>R[i];
	
	int left=0;
	FOR(i,N) {
		int y=-1;
		FOR(x,N) if(vis[x]==0) {
			
			if(M-1-R[x]<L[x]) {
				L[x]=M-1-L[x];
				R[x]=M-1-R[x];
				swap(L[x],R[x]);
			}
			
			if(left>L[x]) {
				L[x]=M-1-L[x];
				R[x]=M-1-R[x];
				swap(L[x],R[x]);
			}
			if(left>L[x]) return _P("NO\n");
			if(y==-1 || L[x]<L[y]) y=x;
		}
		if(y==-1) return _P("NO\n");
		left=R[y]+1;
		vis[y]=1;
	}
	_P("YES\n");
	
}

まとめ

二部グラフとかにならないかなとも思ったけど、想定解は2-SATなのね。