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;
}
然后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;
}
相关文章推荐
- Monkey and Banana(HDU 1069)解题报告(DP - 滚动数组)
- hdu(5119)——滚动数组dp
- HDU 4576(概率DP+滚动数组)
- HDU 4576 (2013杭州邀请赛J题-dp滚动数组优化)
- HDU ~ 1024 ~ Max Sum Plus Plus(DP+滚动数组)
- hdu 1024 Max Sum Plus Plus 一串数字中,m段连续数字最大和 滚动数组+dp
- hdu--1176---dp && 滚动数组优化<porker>
- hdu 4576(概率dp+滚动数组)
- hdu 4576 (简单dp+滚动数组)
- hdu--1520--树形dp<写起来就是深搜啊>-<滚动数组优化>
- HDU 4427 Math Magic【DP+滚动数组】
- hdu 1024 dp滚动数组
- 滚动数组算法 --- DP思想(动态规划)
- [ACM] HDU 4576 Robot (概率DP,滚动数组)
- hdu 3392 利用滚动数组优化的dp
- Happy Matt Friends HDU - 5119 (dp+滚动数组优化)
- hdu 4576 概率dp+滚动数组
- HDU - 5119 Happy Matt Friends dp 滚动数组 异或和 (2014ACM/ICPC亚洲区北京站-重现赛(感谢北师和上交)
- hdu--1421--dp&&滚动数组
- 【HDU 1024】Max Sum Plus Plus(DP+滚动数组优化+最大m段字段之和)