[NOIP模拟题]poker 大根堆 小根堆 贪心

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

 

不会小根堆的点这里

点击这里了解什么是priority_queue 

 

题目

扑克牌

(poker.cpp/in/out 1s 256M)

一副扑克牌有n张牌。一般你买的一副新扑克牌里除了这n张牌外还会有一些张特殊的牌,如果你不小心弄丢了n张牌中的某一张,就可以用特殊牌来代替,但是如果你弄丢两张的话就没有办法了,因为特殊牌上的图案是一样的。现在你得到了很多扑克牌,准确来说,n种牌你各有a1a2、……、an张,同时你还有b张特

殊牌,现在你需要从这些牌中整理出若干副牌供大家使用。整理出的一副牌可以由n种普通牌各一张组成,也可以由n-1种普通牌各一张再加一张特殊牌组成。请你设计出一种方案,整理出尽可能多的牌。

Input

输入包括2

第一行给出nb

第二行给出a1,a2an

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

 

你可能感兴趣的:([NOIP模拟题]poker 大根堆 小根堆 贪心)