Codeforces 201 C. Fragile Bridges

問題

n個の足場がn-1個の橋で一直線上につながっている。
i番目の橋は、a[i]回渡ると壊れる。


今、好きな足場から出発して、壊れていない橋を渡るということを繰り替えす。
橋を渡る回数の最大値は何回か、求めよ。

制約条件

n≦10^5
a[i]≦10^9

方針

渡り方を折れ線で考えると、ループまたは一本の線分になっている。
このような渡り方のうち、最適なものを動的計画法により求める。


動的計画法による。
左からと右からの2回DPする。


まずは左から、
dp[i][0]を、i番目以下の橋のみを使い、最後にiに居て、頂点iからi-1に偶数回渡っているときの、渡る回数の最大値、
dp[i][1]を、i番目以下の橋のみを使い、最後にiに居て、頂点iからi-1に奇数回渡っているときの、渡る回数の最大値とする。


これを更新していくことで、それぞれの最適解がO(n)で求まる。


同様の最大値を右からも求める。
あとは、それぞれの頂点について、左側の最適値と右側の最適値を足したものが、全体の最適解になる。

ソースコード

int n, a[100010];
ll dp[100010][2], dp2[100010][2];

void solve(ll dp[100010][2]){
	rep(i, n - 1){
		if(a[i] > 1)
		dp[i + 1][0] = dp[i][0] + a[i] / 2 * 2;
		if(a[i] > 0)
		dp[i + 1][1] = max(dp[i][0], dp[i][1]) + (a[i] % 2 ? a[i]: a[i] - 1);
	}
}

void run()
{
	cin >> n;
	rep(i, n - 1) cin >> a[i];
	
	solve(dp);
	reverse(a, a + n - 1);
	solve(dp2);
	
	ll ans = 0;
	rep(i, n){
		rep(j, 2) rep(k, 2)
		ans = max(ans, dp[i][j] + dp2[n - i - 1][k]);
		
	}
	cout << ans << endl;
}