01 分数规划

01 分数规划指这样一类问题,对于每个元素,有 ab 两种属性,要求按规则选出一些物品后 ab 最大。

这样的问题可以二分答案 x,看 ab 是否可能 x,二分上界可以设成单个元素 ab 的最大值。

化简不等式会得到 axb0,也就是 (axb)0

这样一来,问题就转化为在该规则下选出的 axb 之和的最大值是否 0

例题:P1404 平均数

分析:可以用 01 分数规划的思想看待这个问题,这里认为每个元素的 a 属性就是这个数的大小,b 属性就是数量,也就是 1,希望 ab 尽可能大。

二分答案后转化为选出的 axb 之和大于等于 0,也就是 ax 之和大于等于 0,就是把所有元素减 x 以后让选出的数之和大于等于 0

注意精度问题,可以在刚开始把每个数都乘以 1000,然后进行二分,整体时间复杂度为 O(nloga)

参考代码
#include <cstdio>
#include <algorithm>
using std::max;
using std::min;
using ll = long long;
const int N = 100005;
int a[N], n, m;
ll sum[N], pre[N];
bool check(int x) {
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i] - x;
pre[i] = min(pre[i - 1], sum[i]);
}
for (int i = m; i <= n; i++)
if (sum[i] - pre[i - m] >= 0) return true;
return false;
}
int main()
{
scanf("%d%d", &n, &m);
int l = 0, r = 0, ans = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]); a[i] *= 1000;
r = max(r, a[i]);
}
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) {
l = mid + 1; ans = mid;
} else {
r = mid - 1;
}
}
printf("%d\n", ans);
return 0;
}

习题:P1419 寻找段落

解题思路

在上一题的基础上多了长度在 [S,T] 的限制。用单调队列维护前缀和的区间最小值。

参考代码
#include <cstdio>
#include <deque>
using std::deque;
const int N = 100005;
const double INF = 1e4;
const double EPS = 1e-5;
int n, s, t, a[N];
double sum[N];
bool check(double x) {
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (a[i] - x);
deque<int> dq;
for (int i = s; i <= n; i++) {
while (!dq.empty() && dq.front() < i - t) dq.pop_front();
while (!dq.empty() && sum[dq.back()] > sum[i - s]) dq.pop_back();
dq.push_back(i - s);
if (sum[i] - sum[dq.front()] > -EPS) return true;
}
return false;
}
int main()
{
scanf("%d%d%d", &n, &s, &t);
double l = -INF, r = INF;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
while (r - l > EPS) {
double mid = (l + r) / 2;
if (check(mid)) {
l = mid;
} else {
r = mid;
}
}
printf("%.3f\n", l);
return 0;
}
posted @   RonChen  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示