1. 程式人生 > 實用技巧 >CodeForces - 908F New Year and Rainbow Roads

CodeForces - 908F New Year and Rainbow Roads

\(\text{Solution}\)

首先,紅點只能與紅點和綠點相連,藍點只能與藍點和綠點相連。

假設兩個相鄰綠點(這裡的相鄰是編號上的相鄰)中間一堆紅點和藍點,我們一定把紅點藍點分別順次連線就像這樣:

顯然紅藍點這樣連成一條鏈再連上綠點要比一個個連上綠點要優。

我們繼續考慮上圖,發現並不需要連這麼多條邊。我們可以選擇刪除一條 \((G,G)\) 或一條端點有紅點的和一條端點有藍點的,取個 \(\min\) 就是這一段的答案,最後累加起來就醒了。

\(\text{Code}\)

#include<cstdio>
#include<iostream>
using namespace std;

int n, ans, x[(int) 3e5 + 2], maxR, maxB, lastR, lastB, lastG;

int read() {
	int x = 0, f = 1; char s;
	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
	while(s >= '0' && s <= '9') {
		x = (x << 1) + (x << 3) + (s ^ 48);
		s = getchar();
	}
	return x * f;
}

int main() {
	char op;
	n = read();
	for(int i = 1; i <= n; ++ i) {
		x[i] = read(); op = getchar();
		if(op == 'G' || op == 'R') {
			if(lastR) ans += x[i] - x[lastR], maxR = max(maxR, x[i] - x[lastR]);
			lastR = i;
		}
		if(op == 'G' || op == 'B') {
			if(lastB) ans += x[i] - x[lastB], maxB = max(maxB, x[i] - x[lastB]);
			lastB = i;
		}
		if(op == 'G') {
			if(lastG) ans += min(0, x[i] - x[lastG] - maxR - maxB);//之前算的是不連綠點的貢獻
			lastG = i;
			maxR = maxB = 0;
		}
	}
	printf("%d\n", ans);
	return 0;
}