POJ 2976

題意

給n組資料ai,bi,定義累計平均值為:

現給出一個整數k,要求從這n個數中去掉k個數後,最大累計平均值能有多大?(四捨五入到整數)

思路

取n−k個數,使得累計平均值最大。

定義C(x)表示能否取得n−k個數,使得累計平均值≥x。然後二分搜尋最大的x。

可以這樣判斷可行性:

只需要從大到小選取n−k個(100⋅ai−x⋅bi)並求和sum,根據sum≥0來判斷(上述的S表示n−k個元素下標的集合)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
int n, k;
ll a[1000 + 4], b[1000 + 4];
double c[1000 + 4];
bool C(double x) { // 檢驗取出的n-k個數的累計平均值是否能>=x
for (int i = 0; i < n; ++i) c[i] = a[i] * 100 - x*b[i];
sort(c, c + n);
double sum = 0;
for (int i = 0; i < n - k; ++i) sum += c[n - i - 1];
return sum >= 0;
}
void solve() {
double lb = 0, ub = 1000000000000000.0;
for (int i = 0; i < 100; ++i) { // 精度10e-30
double mid = (ub + lb) / 2.0;
if (C(mid)) lb = mid; // 半閉半開區間[lb, ub)
else ub = mid;
}
printf("%.f\n", floor(lb + 0.5)); // 四捨五入
}
int main()
{
while (cin >> n >> k) {
if (n == k && n == 0) break;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
solve();
}
return 0;
}

POJ 3111

題意

給出n個珠寶的vi和wi,從中選出k個珠寶,使得最大,求出這k個珠寶的序列。

思路

同上,排序時需記錄序號。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const double EPS = 1e-6;
int n, k;
int v[100000 + 5], w[100000 + 5];
struct Remian{
double c;
int id;
bool operator<(const Remian&b) const {
return c > b.c;
}
} remain[100000 + 5];
bool C(double x) {
for (int i = 0; i < n; ++i) {
remain[i].c = v[i] - w[i] * x;
remain[i].id = i + 1; // 記錄寶珠編號
}
sort(remain, remain + n);
double sum = 0.0;
for (int i = 0; i<k; ++i) sum += remain[i].c;
return sum >= 0;
}
void solve() {
double lb = 0.0, ub = 1000000000000000.0;
//while (ub - lb > EPS) { // 精度1e-6
for(int i=0; i<80; ++i) { // 精度10e-30
double mid = (lb + ub) / 2.0;
if (C(mid)) lb = mid; // 半閉半開區間[lb, ub)
else ub = mid;
}
for (int i = 0; i < k; ++i) printf(i == 0 ? "%d" : " %d", remain[i].id);
printf("\n");
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; ++i) scanf("%d%d", &v[i], &w[i]);
solve();
return 0;
}