bzoj2101[Usaco2010 Dec]Treasure Chest 藏宝箱*
bzoj2101[Usaco2010 Dec]Treasure Chest 藏宝箱
题意:
给个序列,A与B轮流取数,谁取的数总和大谁赢。每次只能取序列两端,问A能取的数总和最大是多少。假设两人都用最优策略。序列大小≤5000
题解:
dp。f[i][j][0]=max(f[i+1][j][1]+a[i],f[i][j-1][1]+a[j]),f[i][j][1]=min(f[i+1][j][0],f[i][j-1][0])。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define maxn 5010 6 using namespace std; 7 8 inline int read(){ 9 char ch=getchar(); int f=1,x=0; 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 11 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 12 return f*x; 13 } 14 int a[maxn],f[2][maxn][2],n; bool x,y; 15 int main(){ 16 n=read(); inc(i,1,n)a[i]=read(); x=0; y=1; 17 for(int i=n;i>=1;i--){ 18 inc(j,1,n)f[y][j][0]=f[y][j][1]=0; 19 inc(j,i,n){ 20 f[y][j][0]=max(f[x][j][1]+a[i],f[y][j-1][1]+a[j]); 21 f[y][j][1]=min(f[x][j][0],f[y][j-1][0]); 22 } 23 swap(x,y); 24 } 25 printf("%d",f[x][n][0]); return 0; 26 }
20160812