P3143 [USACO16OPEN]钻石收藏家Diamond Collector
题意要注意一点:有两个陈列架!
如果只有一个陈列架,是很容易的。two-pointers直接从左到右跑一下即可。
如果有两个陈列架,就需要进行答案合并了。做法是这样的:
设两个数组:
- \(pre\)数组,\(pre[i]\)表示以\([1,i]\)为右端点时区间长度的最大值。
- \(suf\)数组,\(suf[i]\)表示以\([i,n]\)为左端点时区间长度的最大值。
两个数组分别是前缀最大值和后缀最大值。同样利用一个陈列架的two-pointers的做法。
最后的答案就是\(max_{i=1}^{n+1} pre[i-1] + suf[i]\)。这里的\(i\)相当于拼接点。
代码:
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long
const int maxn = 50005;
int a[maxn];
int pre[maxn], suf[maxn];
int n, k;
void work1() {
for(int r = 1, l = 0; r <= n; r++) {
while(a[r] - a[l + 1] > k) l++;
pre[r] = std::max(pre[r - 1], r - l);
}
}
void work2() {
for(int l = n, r = n + 1; l >= 1; l--) {
while(a[r - 1] - a[l] > k) r--;
suf[l] = std::max(suf[l + 1], r - l);
}
}
int main() {
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
std::sort(a + 1, a + n + 1);
work1();
work2();
int ans = 0;
for(int i = 1; i <= n + 1; i++) {
ans = std::max(ans, pre[i - 1] + suf[i]);
}
cout << ans << endl;
return 0;
}
原文地址:https://www.cnblogs.com/Garen-Wang/p/10381458.html
时间: 2024-11-11 03:26:32