POJ 2010 Moo University - Financial Aid (优先队列/二分答案)

来源:互联网 发布:统计表制作软件 编辑:程序博客网 时间:2024/05/22 13:12

题目大意:

从c(<=1e5)个物品中选出n(奇数 <= 19,999)个物品,使得这n个物品的价值中位数尽量高,且总价格不超过f (<= 2,000,000,000)。

做法1:

  • 把物品按价值排序
  • half表示n/2向下取整
  • low[i]表示前i - 1个物品中价格最小的half个物品的价格和
  • hei[i]表示i之后的物品中价格最小的half个物品的价格和
  • low和hei可用优先队列维护
  • 枚举中间物品即可

代码

NKWBTB Accepted 2592KB 204MS C++ 1154
#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>using namespace std;const int maxc = 1e5 + 10;pair<int, int>p[maxc];long long low[maxc], hei[maxc];int main(){    int n, c, f;    scanf("%d%d%d", &n, &c, &f);    int half = n / 2;    for (int i = 0 ; i < c ; i++)        scanf("%d%d", &p[i].first, &p[i].second);    sort(p, p + c);    {        long long sum = 0;        priority_queue<long long>q;        for (int i = 0 ; i < half ; i++)        {            q.push(p[i].second);            sum += p[i].second;            low[i] = 0x7fffffff;        }        for (int i = half ; i < c ; i++)        {            low[i] = sum;            q.push(p[i].second);            sum += p[i].second - q.top();            q.pop();        }    }    {        long long sum = 0;        priority_queue<long long>q;        for (int i = c - 1 ; i >= c - half ; i--)        {            q.push(p[i].second);            sum += p[i].second;            hei[i] = 0x7fffffff;        }        for (int i = c - half - 1 ; i >= 0 ; i--)        {            hei[i] = sum;            q.push(p[i].second);            sum += p[i].second - q.top();            q.pop();        }    }    int ans = -1;    for (int i = c - 1 ; i >= 0 ; i--)        if (hei[i] + low[i] + p[i].second <= f)        {            ans = p[i].first;            break;        }    printf("%d\n", ans);    return 0;}

做法2:

  • 保存两组信息,一组物品按价值排序,另一组按价格排序
  • 二分中间物品的价格
  • 检查答案是否合法

代码

NKWBTB Accepted 2512KB 235MS C++ 1178
#include <cstdlib>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;const int maxn = 1e5 + 10;struct stu{    int first, second, id;}p[maxn], s[maxn];bool cmp1(const stu &a, const stu &b){return a.first < b.first;}bool cmp2(const stu &a, const stu &b){return a.second < b.second;}int main(){    int n, c ,f;    scanf("%d%d%d", &n, &c, &f);    int half = n / 2;    for (int i = 0 ; i < c ; i++)        scanf("%d%d", &p[i].first, &p[i].second);    sort(p, p + c, cmp1);    for (int i = 0 ; i < c ; i++)        p[i].id = i;    memcpy(s, p, sizeof(stu) * c);    sort(p, p + c, cmp2);    int l = 0, r = c, ans = -1;    while (l < r)    {        int m = (l + r) / 2;        int lc = 0, rc = 0, sum = s[m].second;        for (int i = 0 ; i < c ; i++)        {            if (lc < half && p[i].id < s[m].id && sum + p[i].second <= f)            {                sum += p[i].second;                lc++;            }else if (rc < half && p[i].id > s[m].id && sum + p[i].second <= f)            {                sum += p[i].second;                rc++;            }        }        if (lc < half && rc < half)        {            ans = -1;            break;        }        else if (lc < half)            l = m + 1;        else if (rc < half)            r = m;        else{            ans = s[m].first;            l = m + 1;        }    }    printf("%d\n", ans);    return 0;}
0 0