[NOIP模拟题]poker 大根堆 小根堆 贪心
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
不会小根堆的点这里
点击这里了解什么是priority_queue
题目:
扑克牌
(poker.cpp/in/out 1s 256M)
一副扑克牌有n张牌。一般你买的一副新扑克牌里除了这n张牌外还会有一些张特殊的牌,如果你不小心弄丢了n张牌中的某一张,就可以用特殊牌来代替,但是如果你弄丢两张的话就没有办法了,因为特殊牌上的图案是一样的。现在你得到了很多扑克牌,准确来说,n种牌你各有a1、a2、……、an张,同时你还有b张特
殊牌,现在你需要从这些牌中整理出若干副牌供大家使用。整理出的一副牌可以由n种普通牌各一张组成,也可以由n-1种普通牌各一张再加一张特殊牌组成。请你设计出一种方案,整理出尽可能多的牌。
Input
输入包括2行
第一行给出n和b
第二行给出a1,a2…an。
1<=n<=1000000,牌的数量<=10^6
Output
输出最多能整理出的牌的副数。
Sample Input
5 5
5 5 5 5 5
Sample Output
6
【数据规模】
对于20%的数据 1<=n<=100。牌的数量小于100。
对于40%的数据 1<=n<=3000
对于100%的数据 1<=n<=1000000 牌的数量<=10^6
本题样例注意事项:特殊牌每次只能使用一次
一般思维:
考虑不断求最小值,再拿a[i]-min ,看最大是多少。
但是在N=1e6的范围下,此做法是O(N^2)的,显然会TLE。所以只能逆向思维。
逆向思维:
一样的先求最小值,但可以拿一个小根堆来维护,用当前最小值+使用的一张特殊牌。这样就只需要输出栈顶元素即可。
样例深度剖析:
拿个样例来说吧,比如五种牌各有1 2 3 4 5张,有四张特殊牌。设ans代表目前使用了几张特殊牌。
将五种普遍牌丢到堆里。取出最少的一张,也就是1出来。然后给它配一张特殊牌,再丢到堆里,ans=1
堆中有2 2 3 4 5.然后再取出最小的一张,也就是2出来。然后给它配一张特殊牌,再丢到堆里,ans=2
堆中有2 3 3 4 5 然后再取出最小的一张,也就是2出来。然后给它配一张特殊牌,再丢到堆里,ans=3
堆中有3 3 3 4 5.
当我们取出堆中的最小的两个数字3 3时,发现它们均等于ans,说明,其实这两堆牌其实是都已用完了的
此时如果再要派特殊牌的话,则一次要派两张了。与题意不合了。
code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+10; 4 int a[maxn],ans=0; 5 priority_queue<int,vector<int>,greater<int> >q; 6 inline int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 10 return x*f; 11 } 12 int main(){ 13 int n=read(),b=read(); 14 for(int i=1;i<=n;i++){ 15 a[i]=read(); 16 q.push(a[i]); 17 } 18 for(int i=1;i<=b;i++){ 19 ans++; 20 int x=q.top(); 21 q.pop(); 22 x++; 23 q.push(x); 24 int x1=q.top(); 25 q.pop(); 26 int x2=q.top(); 27 q.pop(); 28 q.push(x1); 29 q.push(x2); 30 if(ans==x2&&ans==x1){ 31 break; 32 } 33 } 34 printf("%d\n",q.top()); 35 return 0; 36 }