题目链接
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;
}