Codeforces 976D - Resource Distribution(贪心 + 二分)


题目链接

http://codeforces.com/contest/967/problem/D


题目大意

能否用n个服务器同时为两个任务分配资源。
用k个服务器分配任务量为S的任务时,占用每个服务器S/k1的资源。
每个服务器只能分配到一个任务。


解题思路

降维,优先将大额服务器分配给一个任务,再枚举另一个任务需要的服务器数。

比如,优先将k1个大额的服务器分配给S1,即任务S1最少需要k1个服务器:
具体做法为,对服务器按资源升序排序,从小到大枚举k1,二分找到第一个资源大于等于S1/k1的服务器,设其位置为p,如果p + k1 - 1 <= n,说明p及之后的k1个服务器均可分配S1,此时的k1也是最小的。
找到p后,我们不妨固定最后k1个服务器分配S1,即将[p, p + k1 - 1]后移至[n - k1 + 1, n],以便最大限度分配S2。
然后枚举分配S2的服务器数k2,二分找到第一个资源大于等于S2/k2的服务器,设其位置为q,如果q + k1 + k2 - 1 <= n,说明q及之后的k2个服务器均可分配S2,同时不与最后k1个服务器重合。

如果没有k2能满足S2,说明应优先将大额服务器分配给S2,先确定k2,再枚举k1即可,步骤同上。

总时间复杂度O(nlogn)。


AC代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 300010;

int n;
double x1, x2;

struct Node{
    int id;
    double x;
    bool operator < (const Node &nd) const{
        return x < nd.x;
    }
}a[MAXN];

bool check1(int k1, double x2)
{
    for(int k2 = 1; k2 <= n - k1; k2 ++){
        double p2 = x2 / k2;
        int q = lower_bound(a + 1, a + n + 1, Node{0, p2}) - a;
        if(q + k1 + k2 - 1 <= n){
            puts("Yes");
            printf("%d %d\n", k1, k2);
            for(int i = n - k1 + 1; i <= n; i ++)
                printf("%d ", a[i].id);
            puts("");
            for(int i = q; i <= q + k2 - 1; i ++)
                printf("%d ", a[i].id);
            puts("");
            return true;
        }
    }
    return false;
}

bool check2(int k2, double x1)
{
    for(int k1 = 1; k1 <= n - k2; k1 ++){
        double p1 = x1 / k1;
        int p = lower_bound(a + 1, a + n + 1, Node{0, p1}) - a;
        if(p + k1 + k2 - 1 <= n){
            puts("Yes");
            printf("%d %d\n", k1, k2);
            for(int i = p; i <= p + k1 - 1; i ++)
                printf("%d ", a[i].id);
            puts("");
            for(int i = n - k2 + 1; i <= n; i ++)
                printf("%d ", a[i].id);
            puts("");
            return true;
        }
    }
    return false;
}

int main()
{
    cin >> n >> x1 >> x2;
    for(int i = 1; i <= n; i ++){
        a[i].id = i;
        scanf("%lf", &a[i].x);
    }
    sort(a + 1, a + n + 1);
    int k1 = 1;
    for(; k1 <= n - 1; k1 ++){
        double p1 = x1 / k1;
        int p = lower_bound(a + 1, a + n + 1, Node{0, p1}) - a;
        if(p + k1 - 1 <= n) break;
    }
    int k2 = 1;
    for(; k2 <= n - 1; k2 ++){
        double p2 = x2 / k2;
        int q = lower_bound(a + 1, a + n + 1, Node{0, p2}) - a;
        if(q + k2 - 1 <= n) break;
    }
    if(!check1(k1, x2) && !check2(k2, x1)) puts("No");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Hrbust_cx/article/details/80183656