您的位置:首页 > 其它

NOIP模拟(20171030)T2 游戏

2017-11-01 08:41 495 查看
n个物品,每个物品权值为ai(1≤i≤n),两人按给定顺序轮流拿物品,先手先拿1或2个物品。然后若上一个人拿了k个物品,这一个人必须拿k或k+1个物品,若剩余物品不足k个,游戏结束。

两个人都尽可能使自己拿的权值比别人大,游戏结束后,先手拿的权值比后手多多少(假设两个人都绝顶聪明)那还要我干嘛

n≤20000

考虑dp:dp[i][j] 表示现在从第i个物品开始拿,上一个人拿了j 个,能使自己比对方多拿权值的最大值,则:

dp[i][j]=max(sum[i+j−1]−dp[i+j][j],sum[i+j]−dp[i+j+1][j+1]))−sum[i−1]

然后注意j 是 O(i√)级别的,否则会MLE

#include<bits/stdc++.h>
using namespace std;
inline int getint(){
int x=0,p=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')p=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^'0');
c=getchar();
}
return x*p;
}
int dp[20005][205];
int sum[20005];
inline void work(){
int n=getint();
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;++i){
sum[i]=sum[i-1]+getint();
}
sum[n+1]=-0x3fffffff;
for(int i=n;i>=1;--i){
int top,s=0;
for(top=0;s<=i;++top,s+=top);
for(int j=top;j;--j){
if(i+j-1>n)continue;
dp[i][j]=max(sum[i+j-1]-dp[i+j][j],sum[i+j]-dp[i+j+1][j+1])-sum[i-1];
}
}
//  for(int i=1;i<=n;++i){
//      for(int j=1;j<=3;++j){
//          cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
//      }
//  }
cout<<dp[1][1]<<"\n";
}
int main(){
int t=getint();
while(t--){
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: