您的位置:首页 > 其它

codeforces 731E (优先队列 DP)

2016-10-18 20:29 423 查看

题目链接:点击这里

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

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

其中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
[0] = dp
[1] = 0;
while (!q1.empty ()) q1.pop (); while (!q2.empty ()) q2.pop ();
q1.push (dp
[1]+sum
);
q2.push ((node) {dp
[0]-sum
});
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: