Official

C - Lock All Doors Editorial by cn449


開閉操作について、開いている鍵を閉める操作を 閉操作、閉まっている鍵を開ける操作を 開操作 と呼ぶこととします。

開閉操作の回数が最小となるとき、閉操作の後に開操作を行うことはないとしてよいです。これは、開操作を行う鍵の集合を決め打ったとき、それらに対してまず開操作を行うとしてよいことからわかります。特に、同じ鍵に対して開操作と閉操作はいずれも高々 \(1\) 回しか行いません。

閉操作の回数は開操作の回数とはじめに開いていた鍵の個数の和なので、開操作の回数として考えられる最小値を求めればよいです。

すべてのドアの鍵を閉まった状態にできるための必要十分条件は開操作をすべて行った後に開いているドアの鍵の番号の集合が \(\lbrace i \mid X \leq i \leq Y \rbrace (X \leq R, R - 1 \leq Y)\) の形になっていることです。

したがって、\(L_i = 0\) なる最小の \(i\)\(x\)、最大の \(i\)\(y\) として \(x \leq R - 1\) のときドア \(x, x + 1, \ldots, R - 1\) の鍵がすべて開くような操作を行い、\(y \geq R\) のときドア \(R, R + 1, \ldots, y\) の鍵がすべて開くような操作を行えばよいです。

実装例

#include <bits/stdc++.h>
using namespace std;

int main() {
	int n, r;
	cin >> n >> r;
	vector<int> l(n);
	for (int i = 0; i < n; i++) cin >> l[i];
	int x = n, y = 0;
	for (int i = 0; i < n; i++) {
		if (l[i] == 0) {
			x = i;
			break;
		}
	}
	for (int i = n - 1; i >= 0; i--) {
		if (l[i] == 0) {
			y = i;
			break;
		}
	}
	int open = count(l.begin(), l.end(), 0);
	int t = 0;
	if (x <= r - 1) for (int i = x + 1; i < r; i++) if (l[i] == 1) t++;
	if (y >= r) for (int i = r; i < y; i++) if (l[i] == 1) t++;
	int ans = 2 * t + open;
	cout << ans << '\n';
}

posted:
last update: