题解:P4734 [BalticOI 2015] Hacker
题意
有一个长度为
思路
不难发现 Alice 和 Bob 最终都会取到两端连续的区间且正好将整个
首先肯定要破环为链,直接复制两倍。
然后考虑他们的最优策略。Alice 选择起点时我们显然没有什么好的策略,我们考虑 Bob 选什么起点能使 Alice 取到最小值。我们假设 Alice 的起点为
因此我们只需要枚举每个
代码
这里选择的是单调队列搭配前缀和实现。其他很多数据结构也可以维护,但不建议使用线段树。
#include<bits/stdc++.h>//代码很丑,轻喷
#define int long long//_______,________.
#define N 3 * 500000 + 39
using namespace std;
int n, v[N], qzh[N], w[N], ans;
deque<int>q;
signed main()
{
ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> v[i];
v[n + i] = v[i];
v[2 * n + i] = v[i];//为什么要复制三倍,因为作者写太丑了qwq
}
for(int i = 1; i <= 3 * n + 1; i ++)//前缀和
{
qzh[i] = qzh[i - 1] + v[i];
}
for(int i = 1; i + (n + 1) / 2 - 1 <= 3 * n + 1; i ++)//处理出以每个节点为左端点长度为ceil(n/2)的区间的和
{
w[i] = qzh[i + (n + 1) / 2 - 1] - qzh[i - 1];
}
for(int i = 1 - (n + 1) / 2 + 1 + n; i != n + 1; i ++) //单调队列,不会的可以去看滑动窗口(当然换成ST表等好理解的也可以)
{
while(!q.empty() && w[i] <= w[q.back()])
{
q.pop_back();
}
q.push_back(i);
}
for(int i = n + 1; i <= 2 * n; i ++)
{
while(!q.empty() && w[i] <= w[q.back()])
{
q.pop_back();
}
if(!q.empty() && q.front() + (n + 1) / 2 - 1 < i)
{
q.pop_front();
}
q.push_back(i);
ans = max(ans, w[q.front()]);//虽然单调队列里是递减的,但是这里要取max
}
cout << ans;
return 0;
}
AC 记录。