Typical DP Contest L - 猫

問題

一次元上に猫1, ..., Nをこの順に並べる。
猫同士には仲のよさf[i][j]が定まっている。


i番の猫の幸福度は、i番目の猫から距離1にいる猫の仲のよさの総和である。
猫を最適に並べたときの、幸福度の総和の最大値を求めよ。

制約条件

N≦1000
f[i][j]の絶対値≦1000

方針

dp[i][j] := 猫iまで並べたとき、i番目の猫から距離1以内にいる猫のうち最も小さい番号がjであるようなときの幸福度の総和の最大値


として、これを更新するDP.
dp[i][j] = max{dp[i - 1][k] + sum[j][i] | k ≦ j }という漸化式になる。
kを全部見るとO(n^3)でTLEになるが、
sumを前計算しておき、max{dp[i - 1][k]}はjが増えるたびにmaxをとって更新していけば
O(n^2)で計算できる。

ソースコード

昔の自分はトチ狂ってsegment木を使ったようだ。

int n, f[1000][1000];
int N, dat[2][2048], sum[1000][1000];
 
inline void init(int *dat){
	rep(i, 2*N) dat[i] = -inf;
}
inline void update(int *dat, int i, int v){
	i += N - 1;
	dat[i] = max(dat[i], v);
	while(1){
		i = (i - 1) / 2;
		dat[i] = max(dat[i * 2 + 1], dat[i * 2 + 2]);
		if(i == 0) break;
	}
}
inline int query(int *dat, int a, int b, int k, int l, int r){
	if(a <= l && r <= b) return dat[k];
	if(b <= l || a >= r) return -inf;
	
	int lch = query(dat, a, b, k * 2 + 1, l, (l + r) / 2);
	int rch = query(dat, a, b, k * 2 + 2, (l + r) / 2, r);
	return max(lch, rch);
}
 
int main(){
	cin >> n;
	rep(i, n) rep(j, n) cin >> f[i][j];
	rep(i, n) for(int j = i; j < n; j++) sum[i][j] = (j ? sum[i][j - 1] : 0) + f[i][j];
	
	for(N = 1; N < n; N *= 2);
	int cur = 0, next = 1;
	
	init(dat[0]);
	rep(i, n) update(dat[0], i, sum[0][i]);
	
	for(int i = 1; i < n; i++){
		init(dat[next]);
		
		for(int j = i; j < n; j++){
			int q = query(dat[cur], i - 1, j + 1, 0, 0, N);
			update(dat[next], j, q + sum[i][j]);
		}
		swap(cur, next);
	}
	cout << 2 * query(dat[cur], n-1, n, 0, 0, N) << endl;
	
	return 0;
}

普通に書くとこんなかんじ

int n, f[1000][1000];
ll dp[1001][1001];

int main(){
	scanf("%d", &n);
	rep(i, n) rep(j, n) scanf("%d", f[i] + j);
	
	rep(i, n + 1) rep(j, n + 1) dp[i][j] = -inf;
	dp[0][0] = 0;
	
	rep(i, n){
		vector<ll> sum(1, 0LL);
		rep(j, i) sum.pb(sum.back() + f[i][i - j - 1]);
		reverse(all(sum));
		
		ll mx = -inf;
		
		rep(j, i + 1){
			
			mx = max(mx, dp[i][j]);
			dp[i + 1][j] = mx + sum[j];
			
		}
	}
	cout << *max_element(dp[n], dp[n] + n) * 2 << endl;
	
	return 0;
}