USACO17DEC - Haybale Feast

【LuoguP4085】【USACO17DEC】Haybale Feast
题目链接: https://www.luogu.org/problemnew/show/P4085

引言

好像教练说要考线段树和树状数组, 然后看到了这个题

这道题可以练习各种数据结构的基础操作…

我就浪费了大把时间用各种算法来A这道题

分析

先看这个 $ \sum_{k=i}^{j} F_k \geqslant M $

这个一眼看上去就是前缀和了.静态的话直接普通的前缀和$ O(n) $ 预处理, $ O(1) $ 查询就行了,应该是时间复杂度最低的了.

至于这个 $ max(S_i,S_{i+1},…,S_{j-1},S_j) $

维护方法就比较多了,可以用线段树,分块,ST表,我没有写树状数组,因为太麻烦了.

然后我就浪费了好多时间来用不同的算法A这道题…

这道题还有一个性质, 关于找i和j, 不需要 $ O(n^2) $ 的复杂度来枚举区间, 我给出下面这个式子

$$ max(s_i, s_{i + 1}, s_{i + 2}) <= max(s_i, s_{i + 1}, s_{i + 2}, s_{i + 3}) $$

这个式子根本不用推, 一眼看上去肯定就成立了

那么根据这个性质, 我们枚举i的值, 只需要找到一个对应的j就行了,这个j一定是满足条件且最小的那个了

满足条件只需要

$$ Sumf_j - sumf_i >= m $$

注: Sumf代表f数组的前缀和

那么我们可以用 $ O(logn) $ 的复杂度二分查询这个j了

我们其实不需要自己写二分查找,根据上面的不等式,移一下项,就变成了

$$ Sumf_j >= m + sumf_i $$

然后使用STL自带的lower_bound函数就可以了

维护区间最大值我建议写ST表, 毕竟静态查询时间复杂度 $ O(1) $, 你也可以写其他的, 我竟然写了三种数据结构.

代码

这个代码是线段树 + 前缀和, 评测详情 418ms / 6MB

ST_Table为ST表的代码, 评测详情 328ms / 9.53MB

Sqrt为分块,实在没找到英文名, 评测详情 1049ms / 7.65MB

m 和 前缀和要开long long, 其他的可以用int, 懒得话就全部 long long 吧

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
int n, f[100001], s[100001];
ll m;
inline int maxi(int a, int b) {
return a > b ? a : b;
}
inline int mini(int a, int b) {
return a < b ? a : b;
}
namespace PrefixSum {
// prefixsum for f
ll sumf[100001];
void init() {
for(int i= 1; i <= n; i++) sumf[i]= sumf[i - 1] + f[i];
return;
}
} // namespace PrefixSum
namespace ST_Table {
// ST_Table for s
int maxs[100001][18], _log2[100001];
void init() {
for(int i= 1; i <= n; i++) maxs[i][0]= s[i], _log2[i]= _log2[i - 1] + (i >= (1 << (_log2[i - 1] + 1)));
for(int j= 1; j < 18; j++)
for(int i= 1; i + (1 << j) <= n; i++) maxs[i][j]= maxi(maxs[i][j - 1], maxs[i + (1 << (j - 1))][j - 1]);
return;
}
int query(int l, int r) {
int __log2= _log2[r - l + 1];
return maxi(maxs[l][__log2], maxs[r - (1 << __log2) + 1][__log2]);
}
} // namespace ST_Table
namespace Sqrt {
// Sqrt for s
int blocks, maxs[100001], block[100001], bl[100001], br[100001];
void init() {
blocks= sqrt(n);
int cnt= n / blocks + (n % blocks & 1);
for(int i= 1; i <= n; i++) block[i]= (i - 1) / blocks + 1;
for(int i= 1; i <= cnt; i++) bl[i]= (i - 1) * blocks + 1, br[i]= i * blocks;
br[cnt]= mini(n, br[cnt]);
for(int i= 1; i <= cnt; i++)
for(int j= bl[i]; j <= br[i]; j++) maxs[i]= maxi(maxs[i], s[j]);
return;
}
int query(int l, int r) {
int x= block[l], y= block[r], ans= 0;
for(int i= x + 1; i < y; i++) ans= maxi(ans, maxs[i]);
for(int i= l; i <= br[x]; i++) ans= maxi(ans, s[i]);
for(int i= bl[y]; i <= r; i++) ans= maxi(ans, s[i]);
return ans;
}
} // namespace Sqrt
namespace SegmentTree {
// SegmentTree for s
int maxs[100001 << 2];
void build(int nown, int l, int r) {
if(l == r) {
maxs[nown]= s[l];
return;
}
int mid= (l + r) >> 1;
build(nown << 1, l, mid);
build(nown << 1 | 1, mid + 1, r);
maxs[nown]= maxi(maxs[nown << 1], maxs[nown << 1 | 1]);
return;
}
int query(int nown, int l, int r, int ml, int mr) {
if(ml <= l && r <= mr) return maxs[nown];
int ans= 0, mid= (l + r) >> 1;
if(mid >= ml) ans= maxi(ans, query(nown << 1, l, mid, ml, mr));
if(mid < mr) ans= maxi(ans, query(nown << 1 | 1, mid + 1, r, ml, mr));
return ans;
}
inline void init() {
build(1, 1, n);
return;
}
inline int query(int l, int r) {
return query(1, 1, n, l, r);
}
} // namespace SegmentTree
int ans= 0x7f7f7f7f;
int main() {
scanf("%d%lld", &n, &m);
for(int i= 1; i <= n; i++) scanf("%d%d", f + i, s + i);
PrefixSum::init(), SegmentTree::init();
for(int i= 1; i <= n; i++) {
ll r= lower_bound(PrefixSum::sumf + i, PrefixSum::sumf + n + 1, m + PrefixSum::sumf[i - 1]) - PrefixSum::sumf;
if(r != n + 1) ans= mini(ans, SegmentTree::query(i, r));
}
printf("%d\n", ans);
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×