TopCoder SRM 602 Div1 Easy TypoCoderDiv1

問題

Typocoderにn回参加する。
初期のレーティングはXで、i回目のコンテストで本気を出すとD[i]レーティングが上がり、
本気を出さないとD[i]レーティングが下がる。
ただし、レーティングが0未満になったときは、0になるとする。


レーティングが2200以上の人はbrown coderで、
2200未満の人はciel coderである。


コンテスト終了時にbrown coderであることが2回連続しないようにしたい。
(n回のコンテスト終了時にbrownになっていてもよい)
この条件の下で、色が変化する回数を最も増やしたい。
回数の最大値を求めよ。

制約条件

n≦50
D[i]≦10億
X≦2200

方針

D[i]が小さかったらdp[コンテスト何回やったか][レート]:=色変化の回数の最大値
みたいなDPが出来るが、D[i]が大きい。


けれどよく考えると、一度2200を超えても次のコンテストでは2200未満になるので、
色が変化するときは二回の動きをまとめて処理すれば結局2200未満のレートの部分だけを覚えるDPが出来る。

ソースコード

int dp[51][2300];

class TypoCoderDiv1 {
	public:
	int getmax(vector <int> D, int X) {
		int n = D.size();
		int ans = 0;
		memset(dp, -1, sizeof(dp));
		dp[0][X] = 0;
		
		rep(i, n){
			rep(j, 2300) if(dp[i][j] >= 0){
				if(j + D[i] >= 2200){
					if(i == n - 1) ans = max(ans, dp[i][j] + 1);
					else if(j + D[i] - D[i + 1] < 2200){
						int nj = max(0, j + D[i] - D[i + 1]);
						dp[i + 2][nj] = max(dp[i + 2][nj], dp[i][j] + 2);
					}
				}
				else dp[i + 1][j+ D[i]] = max(dp[i + 1][j + D[i]], dp[i][j]);
				dp[i + 1][max(0, j - D[i])] = max(dp[i + 1][max(0, j - D[i])], dp[i][j]);
			}
		}
		rep(i, 2300) ans = max(ans, dp[n][i]);
		return ans;
	}
};