您的位置:首页 > 其它

HDU 6199(DP)补题+一个超级有用的滚动数组思想

2017-09-12 17:12 429 查看
恩,这个题目开始想着应该不能用dp来写,因为后面的状态对前面的状态有影响

然后emmmm,只有后面的状态对前面的状态有影响,这个。。。有点背锅了

现在说正解

dp[p][i][k]就是人p,在第i个宝石(这个宝石未取到)至少要取k个的差值

那么我们的状态转移方程就出来了

假设p=1代表Alice

       p=0代表Bob

dp[1][i][k]=max(dp[0][i+k][k]+sum[i+k-1]-sum[i-1],dp[0][i+k+1][k+1]+sum[i+k]-sum[i-1])

dp[0][i][k]=min(dp[1][i+k][k]-(sum[i+k-1]-sum[i-1]),dp[1][i+k+1][k+1]-(sum[i+k]-sum[i-1]))

这个其实很好推的,只要注意一下边界条件什么的就好了

然后发现MLE了

我们发现k最多只能到200

那么我们的第i个状态是由后面的<k个的状态推出来的

所以可以想到使用滚动数组

然后发现T了,真的是mmp呀

看了下别人的博客

原来取模的时候他用的是&255

然后255=11111111,毕竟位运算比取模运算快很多嘛,然后就过了

现在放上AC代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

int sum[21100];
int dp[2][256][220];

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);

sum[0]=0;
for (int k=1;k<=n;k++)
{
int save;
scanf("%d",&save);
sum[k]=sum[k-1]+save;
}

//dp[x][i][k]表示这个人,从第i个开始选,至少选k个的Alice-Bob
memset(dp,0,sizeof(dp));

int maxk=(int)sqrt(n*2)+1;

for (int i=n;i>=1;i--)
{
for (int k=1;k<=maxk;k++)
if (i+k-1>n) break;
else
{
int save2;
dp[1][i&255][k]=dp[0][(i+k)&255][k]+sum[i+k-1]-sum[i-1];
dp[0][i&255][k]=dp[1][(i+k)&255][k]-(sum[i+k-1]-sum[i-1]);

if (i+k<=n)
{
save2=dp[0][(i+k+1)&255][k+1]+sum[i+k]-sum[i-1];
if (dp[1][i&255][k]<save2)
dp[1][i&255][k]=save2;

save2=dp[1][(i+k+1)&255][k+1]-(sum[i+k]-sum[i-1]);
if (dp[0][i&255][k]>save2)
dp[0][i&255][k]=save2;
}
//1是Alice 他希望差值越大越好
//0是Bob希望值越小越好
}
}

printf("%d\n",dp[1][1][1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: