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; }