OJ: POJ
题目 ID: 2976
难度:普及+/提高-
标签:01分数规划
创建: 2026-01-05 15:01
更新: 2026-10-07 12:15
后置题目
题目解析
题意:有
1. 二分性(单调性)
- 二分性:如果分数
可以达到,那么比 更小的分数都能达到(沿用同一组考试即可)。即 成立时,任意 也都成立。因此可以对答案 本身二分,我们要让 尽可能大。 - 答案范围:
(输出时再乘 100)。
于是问题变成:给定
2. 分数规划变形(关键观察)
验证
两边乘正数
定义
3. check 函数:贪心取最大的 个
要让
代码对应:_sum(x) 计算所有 check(mid) 返回 _sum(mid) >= 0。
4. 二分与输出
- 在
上固定二分 100 次:每次取 , check(mid)为真则l = mid,否则r = mid。100 次后区间长度缩到,远超输出精度需要。 - 最后输出
(int)(l*100 + 0.5),即四舍五入后的百分比。
5. 复杂度
每次 check 需要
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github : https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* date: 2026-01-05 15:28:43
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e6+5;
int n,k;
int a[maxn];
int b[maxn];
double v[maxn]; // v[i] = a[i] - x * b[i]
double _sum(double x) {
for(int i = 1;i <= n ;++i ) // i: 1->n
{
v[i] = a[i] - x * b[i];
}
std::sort(v+1,v+1+n);
// 这里是贪心, 选的越少越好, 哪就选 n-k个
double s = 0;
for(int i = n;i >k;--i ) // i: 1->n
s+= v[i];
return s;
}
//检查pos位置的值是否符合要求
bool check(double mid){
return _sum(mid) >= 0;
}
signed main () {
ios::sync_with_stdio(false); cin.tie(0);
while (1) {
std::cin >> n >> k;
if( n == 0 &&k == 0) break;
for(int i = 1;i <= n ;++i ) // i: 1->n
std::cin >> a[i];
for(int i = 1;i <= n ;++i ) // i: 1->n
std::cin >> b[i];
// 枚举分数
double l = 0 , r = 1;
//100 次 应该可以了
for(int i = 0 ;i < 100 ;i++)
{
double mid = (l+r) / 2;
if( check(mid))
l = mid;
else
r = mid;
}
std::cout << (int)(l*100 + 0.5) << "\n";
}
return 0;
}