zoukankan      html  css  js  c++  java
  • BZOJ[3728]PA2014 Final Zarowki

    有n个房间和n盏灯,你需要在每个房间里放入一盏灯。每盏灯都有一定功率,每间房间都需要不少于一定功率的灯泡才可以完全照亮。 

    你可以去附近的商店换新灯泡,商店里所有正整数功率的灯泡都有售。但由于背包空间有限,你至多只能换k个灯泡。
    你需要找到一个合理的方案使得每个房间都被完全照亮,并在这个前提下使得总功率尽可能小。

    Input

    第一行两个整数n,k(1<=k<=n<=500000)。
    第二行n个整数pi,表示你现有的灯泡的功率。
    第三行n个整数wi,表示照亮每间房间所需要的最小功率。

    Output

    如果无法照亮每间房间,仅输出NIE。
    否则输出最小的总功率。

    Sample Input

    6 2

    12 1 7 5 2 10

    1 4 11 4 7 5

    Sample Output

    33
    HINT

    解释:将2和10换成4和4。配对方案为1-1,4-4,4-4,5-5,7-7,11-12。

    Sol:

    先将两个数列降序排序出来得到

    A:1 2 5 7 10 12

    B:1 4 4 5 7 11

    对于B数列从后向前做,

    对于11,将大于11的丢到一个小根堆中,也就只有12这个数字,弹出12来匹配11

    差值1丢到大根堆中

    对于7,将>=7的丢到小根堆中,丢进去7和10,弹出7来匹配7

    对于5,将>=5的丢到小根堆中,丢进去5,弹出5来匹配5

    对于4,没有丢什么到小根堆中,堆中还有10,用10来匹配4,差值6丢到一个大根堆中

     对于4,小根堆中没有元素了,于是使用一次商店。

    对于1,用1来匹配。

    以上代价为39.

    由于还有一次商店使用权没用过,于是弹出大根堆的值为6

    ans=39-6=33

    /*
    将手头上有的亮度a及要求的房间亮度b都降序排出来
    一个个拿出要求的亮度,将大于等于它的a的值一个个丢到小根堆q里
    然后看下q是否为空,如果为空说明此时要去商店拿一个亮度与当前一致的
    如果q不为空,则弹出堆顶值,并将两者的差值加到一个大堆根q1中
    全部做完后,如果还有名额去商店拿灯泡,则弹出q1的堆顶 
    */
    #include<bits/stdc++.h>
    #include<cstdio>
    #include<queue>
    #define N 500050
    using namespace std;
    priority_queue<int,vector<int>,greater<int> >q;
    priority_queue<int,vector<int>,less<int> >q1;
    inline bool cmp(int a,int b)
    {
        return a>b;
    }
    int a[N],b[N];
    int n,k,t,x;
    long long ans;
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) 
            scanf("%d",a+i);
        for(int i=1;i<=n;i++) 
            scanf("%d",b+i);
        sort(a+1,a+n+1,cmp);//手头上的灯,降序排好 
        sort(b+1,b+n+1,cmp);//要求的灯的亮度 
        t=1;
        for(int i=1;i<=n;i++)
        {
            while(a[t]>=b[i]&&t) //将大于第i个所要求的灯亮度的灯丢到小根堆里 
                 q.push(a[t++]);
            if(q.empty()) //如果堆为空 
            {
                ans=ans+b[i];//使用当前亮度 
                if(k) //如果还可以换灯泡 
                        k--;
                else //堆中没有大于当前要求亮度的,又没办法去商店拿,于是无解 
                       return printf("NIE"),0;
            }
            else //说明堆中还有元素值大于当前亮度的 
            {
               x=q.top();
               q.pop();
               ans=ans+x;//从小根堆中取出一个大于等于当前要求亮度的且值最小的,用上之 
               q1.push(x-b[i]);//差值放到大根堆中 
            }
         }
        while(k--&&!q1.empty())//如果还可以换灯泡的话 
        {
            ans=ans-q1.top();
        //    cout<<"change it ans is "<<ans<<endl;
            q1.pop();
        }
    return printf("%lld",ans),0;
    }
  • 相关阅读:
    2.17-2.23第一周总结
    10号总结
    9日总结
    8号总结
    7号寒假总结
    6号
    读后感《程序员的修炼之道:从小工到专家》1
    java第二次动手动脑
    回文判断
    二进制的原码,反码以及补码介绍
  • 原文地址:https://www.cnblogs.com/cutemush/p/11684296.html
Copyright © 2011-2022 走看看