[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 }