BZOJ3969. [WF2013]Low Power(二分)

Description
有n个机器,每个机器有2个芯片,每个芯片可以放k个电池。
每个芯片能量是k个电池的能量的最小值。
两个芯片的能量之差越小,这个机器就工作的越好。
现在有2nk个电池,已知它们的能量,我们要把它们放在n个机器上的芯片上,
使得所有机器的能量之差的最大值最小。
Input
第一行,两个正整数,n和k。
第二行,2nk个整数,表示每个电池的能量。
Output
一行一个整数,表示所有机器的能量之差的最大值最小是多少。
Sample Input
2 3
1 2 3 4 5 6 7 8 9 10 11 12
Sample Output
1
Hint
2nk <= 10^6, 1 <= pi <= 10^9。

Source

思路:
二分关键在于check!
这道题目每个机器的值为两个芯片最小值的差,可以推出这两个最小值一定是机器内的数排序后的相邻两个最小的值。

二分机器的最大值mid,那么所有最小值的差都要小于等于mid。我们要尽可能多的找出相差小的值,那么肯定是从原序列中取相邻的两个数作为芯片最小值。

因此判断mid合理的方法是,看原序列能否找到n个相邻数对差值不大于x,并且满足每个数对至少对应2 * k个数(包括数对本身)。

用代码表示就是:i - 2 ≤ cnt * 2 * k, 也就是数对之间间隔不大于2 * k。
i-2表示算完的数
cnt表示算好的数对。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,m,k;
int a[1000005];

bool check(int x)
{

    for(int i = 2,cnt = 0;i <= m,cnt < n;i++)
    {
        if(i - 2 > cnt * 2 * k)return false;
        if(a[i] - a[i - 1] <= x)
        {
            cnt++;
            i++;
        }
    }
    return true;
}

int main()
{
    scanf("%d%d",&n,&k);
    m = 2 * n * k;
    int l = 0,r = 0,ans = 0;
    for(int i = 1;i <= m;i++)
    {
        scanf("%d",&a[i]);
        r = max(a[i],r);
    }
    
    sort(a + 1,a + 1 + m);
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(check(mid))
        {
            ans = mid;
            r = mid - 1;
        }
        else
        {
            l = mid + 1;
        }
    }
    
    printf("%d\n",ans);
    return 0;
}

发布了628 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104029882