bzoj21012101: [Usaco2010 Dec]Treasure Chest 藏宝箱(滚动数组优化dp)
2101: [Usaco2010 Dec]Treasure Chest 藏宝箱
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 592 Solved: 319
[Submit][Status][Discuss]
Description
Bessie and Bonnie have found a treasure chest full of marvelous gold coins! Being cows, though, they can't just walk into a store and buy stuff, so instead they decide to have some fun with the coins. The N (1 <= N <= 5,000) coins, each with some value C_i (1 <= C_i <= 5,000) are placed in a straight line. Bessie and Bonnie take turns, and for each cow's turn, she takes exactly one coin off of either the left end or the right end of the line. The game ends when there are no coins left. Bessie and Bonnie are each trying to get as much wealth as possible for themselves. Bessie goes first. Help her figure out the maximum value she can win, assuming that both cows play optimally. Consider a game in which four coins are lined up with these values: 30 25 10 35 Consider this game sequence: Bessie Bonnie New Coin Player Side CoinValue Total Total Line Bessie Right 35 35 0 30 25 10 Bonnie Left 30 35 30 25 10 Bessie Left 25 60 30 10 Bonnie Right 10 60 40 -- This is the best game Bessie can play.
Input
* Line 1: A single integer: N * Lines 2..N+1: Line i+1 contains a single integer: C_i
Output
* Line 1: A single integer, which is the greatest total value Bessie can win if both cows play optimally.
Sample Input
30
25
10
35
Sample Output
HINT
(贝西最好的取法是先取35,然后邦妮会取30,贝西再取25,邦妮最后取10)
Source
/*
设f[i][j]为[i,j]这段区间先手能获得最大值
初值f[i][i]=a[i],因此要从小区间推大区间。
显然先手要让对手得到的最小,用区间的和减去对手的最小值就是先手的最大值
以为先手操作一次后就成了另一个人先手
所以f[i][j]=sum[j]-sum[i-1]-min(f[i+1][j],f[i][j+1])
炸空间。
可以看出f[][j]只会被f[][j]或者f[][j+1]更新,可以滚动数组压掉一维。
f[0/1][i]表示以i为起点,某段长度的最大值。
转移时先枚举区间长度,f[k^1][i]=sum[j]-sum[i-1]-min(f[k][i],f[k][i+1]);
因为区间长度从小到大枚举,所以枚举到这个长度时右端点为i+len-1,上个长度是i+len-2
所以dp方程里f[k][i]储存的是上个区间长度即f[l][r-1],f[k][i+1]储存的是f[l+1][r])
*/
#include<bits/stdc++.h>
#define N 5001
using namespace std;
int n,m,k,ans,cnt;
int f[2][N],sum[N];
inline int read()
{
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main()
{
freopen("ly.in","r",stdin);
n=read();
for(int i=1;i<=n;i++)
{
sum[i]=read();
f[k][i]=sum[i];sum[i]+=sum[i-1];
}
for(int L=2;L<=n;L++)
{
for(int i=1;i+L-1<=n;i++)
{
int j=i+L-1;
f[k^1][i]=sum[j]-sum[i-1]-min(f[k][i],f[k][i+1]);
}k^=1;
}
printf("%d\n",f[k][1]);
return 0;
}