[bzoj 2017] [Usaco2009 Nov]硬币游戏

  一个多月没更博客了。。(期间明白了自己有多傻逼。

 

  这种问题大概就倒着做...

  f[i][j]:表示考虑剩下的硬币i..n,且之前的人取了j个时,先手最多拿到的钱数。aft[i]:表示硬币i..n的总钱数。

  f[i][j]=aft[i]-min{ f[k][k-i] },(i<k<=min(n,i+2*j))

  k随着j的增加而增加。不同的j只是k的范围不同而已。所以记录一波最小值就可以了。

  时间复杂度O(n²)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=2023;
 7 int f[maxn][maxn];
 8 int aft[maxn],a[maxn];
 9 int i,j,k,n,m;
10  
11 int ra;char rx;
12 inline int read(){
13     rx=getchar(),ra=0;
14     while((rx<'0'||rx>'9'))rx=getchar();
15     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
16 }
17 inline int min(int a,int b){return a<b?a:b;}
18 int main(){
19     n=read();
20     for(i=1;i<=n;i++)a[i]=read();
21     for(i=n;i;i--)aft[i]=aft[i+1]+a[i];
22     for(i=n;i;i--)for(j=(n-i+2)>>1;j<=n;j++)f[i][j]=aft[i];int mn;
23     for(i=n-1;i;i--){
24         mn=1e9,k=i;
25         for(j=1;j<=i;j++){
26             if(k<=n)k++,mn=min(mn,f[k][k-i]);
27             if(k<=n)k++,mn=min(mn,f[k][k-i]);
28             f[i][j]=aft[i]-mn;
29             if(k>n)break;
30         }
31         for(j++;j<=i;j++)f[i][j]=aft[i]-mn;
32     }
33     printf("%d\n",f[1][1]);
34 }
View Code

 

posted @ 2016-06-18 15:19  czllgzmzl  阅读(211)  评论(0编辑  收藏  举报