「POI 2015」WIL-Wilcze doły

假设选中区间 [l,r][l, r],经过题目中的操作,获得的和为该区间的得分,其中最小的成为最小得分 fl,rf_{l,r}

显然得选满 dd 长度

所以对于区间 [l,r][l, r] 只需要知道其中长度为 dd 的最大子段和就可以知道区间的最小得分

当然是用线段树维护啦

学数据结构果然会变傻

发现可以用单调队列维护最大子段和

然后发现若是区间 fl,r>pf_{l, r} > p 则必然有  x<l,y>r   fx,y>p\forall~x<l,y>r~~~f_{x, y} > p

然后就是一道 two-pointer 的题了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, l, r) for (int i = (l); i >= (r); --i)
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::make_pair;
using std::pair;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int, ll> pii;

const int N = 2000010;

ll a[N], s[N];

std::deque<pii> q;

int main() {
#ifdef LOCAL
freopen("input", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
cout.tie(0);
int n, d;
ll p;
cin >> n >> p >> d;
rep(i, 1, n) {
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
int ans = d, l = 1, r = d;
ll c = 0;
q.push_back(pii(1, s[d]));
for (; r <= n; ++r) {
// c += a[r];
c = s[r] - s[r - d];
while (q.size() && q.back().second <= c) q.pop_back();
q.push_back(pii(r - d + 1, c));
c = s[r] - s[l - 1] - q.front().second;
while (c > p) {
++l;
while (q.size() && q.front().first < l) q.pop_front();
c = s[r] - s[l - 1] - q.front().second;
}
ans = std::max(r - l + 1, ans);
// for(q.size() && q.front().first)
}
cout << ans;
return 0;
}

「POI 2015」WIL-Wilcze doły

https://gesrua.xyz/archives/题解/P3594

作者

Gesrua

发布于

2019-07-28

更新于

2020-11-21

许可协议