codeforces 731E (优先队列 DP)

本文介绍了一种使用动态规划解决两人博弈问题的方法,并通过一个具体题目进行了解析。利用单调队列维护状态,实现高效的DP转移。

题目链接:点击这里

题意:给出n个数字,A和B两个人依次选中 1k(k2) ,把他们合并之后自己分数加上这些数的和。求两个人在最右策略下A最多领先B多少。当数字只剩下一个之后游戏马上结束。

dp[i][0/1] 表示前i个数字被合并,现在是A/B先手到最后游戏结束最多领先多少。故A要最大化后继状态的值,B要最小化后继状态的值,转移就很显然了:

dp[i][0]=max{dp[j][1]+sum[j]|i<jn}
dp[i][1]=min{dp[j][0]+sum[j]|i<jn}

其中sum数组是a数组的前缀和。因为每次都用一个最大/小值去更新,所以用两个单调队列维护 dp[i][1]+sum[i] dp[i][0]+sum[i] 即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 200005

long long dp[maxn][2], a[maxn], sum[maxn];
int n;
priority_queue <long long> q1;
struct node {
    long long x;
    bool operator < (const node &a) const {
        return x > a.x;
    }
};
priority_queue <node> q2;

int main () {
    ios::sync_with_stdio (0);
    cin >> n;
    sum[0] = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        sum[i] = sum[i-1]+a[i];
    }
    dp[n][0] = dp[n][1] = 0;
    while (!q1.empty ()) q1.pop (); while (!q2.empty ()) q2.pop ();
    q1.push (dp[n][1]+sum[n]);
    q2.push ((node) {dp[n][0]-sum[n]});
    for (int i = n-1; i >= 1; i--) {
        dp[i][0] = q1.top ();
        dp[i][1] = q2.top ().x;
        q1.push (dp[i][1]+sum[i]);
        q2.push ((node) {dp[i][0]-sum[i]});
    }
    cout << dp[1][0] << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值