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

本文介绍了一个涉及动态规划(DP)的宝石收集问题解决方案。通过详细分析状态转移方程及优化手段,如滚动数组和位运算,成功解决了内存溢出和运行超时的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

恩,这个题目开始想着应该不能用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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值