盒子 贪心
题目:
盒子
(box.cpp/in/out 1s 256M)
小D在玩堆盒子的游戏,每个盒子有一个强度,代表它上方最多能堆多少个
盒子。由于盒子都是一样大的,所以不能在一个盒子上并列放超过一个盒子。
现在小D有n个盒子,第i个盒子的强度为xi。小D想知道,如果他要把这些盒
子全部堆起来,至少要堆多少堆。
Input
第一行读入一个整数n,代表小D有的盒子个数。
第二行读入n个整数,第i个整数xi表示第i个盒子的强度。
Output
一个整数表示小D至少要堆多少堆。
n≤500000,xi≤1000000000。
Sample Input
5
0 2 1 1 2
Sample Output
2
法一:
此题用小根堆来维护。
将所有盒子从小到大排序。然后一个个加,这时不再关心盒子本身的那个所谓堆数的限制
拿样例来说,0 1 1 2 2
将0这个盒子放到堆中,记值为1,代表有一个大小为一个盒子的盒子堆,再看数字1,值大于等于目前,所以可以加到这个盒子堆中,盒子堆的体积变2。对于第三个数字1,其已不能放到第一堆的盒子堆中了,于是另开一堆出来。其中Heap中有两个元素,一个为1,一个为2,对于第四个数字2,显然可以放到第二堆的盒子堆中。。。
初始push值为1,因为无论怎样第一个(必须从小到大排序) 一定可以为1堆,若枚举的值大于等于目前堆顶元素,就加入此堆,否则就另开一个堆,另一个堆顶元素肯定也为1,因为此时另一个堆也有一个元素。
code:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(3) 3 const int N=5e5+10; 4 using namespace std; 5 int n,a[N]; 6 int ans=1; 7 priority_queue< int,vector<int>,greater<int> >q; 8 inline int read(){ 9 int x=0,f=1;char ch=getchar(); 10 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 11 while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 12 return x*f; 13 } 14 inline void write(int x){ 15 char F[200]; 16 int tmp=x>0?x:-x ; 17 if(x<0)putchar('-') ; 18 int cnt=0 ; 19 while(tmp>0) 20 { 21 F[cnt++]=tmp%10+'0'; 22 tmp/=10; 23 } 24 while(cnt>0)putchar(F[--cnt]) ; 25 } 26 int main() 27 { 28 n=read(); 29 for(int i=1;i<=n;i++){ 30 a[i]=read(); 31 } 32 sort(a+1,a+n+1); 33 q.push(1); 34 for(int i=2;i<=n;i++){ 35 int x=q.top(); 36 if(x<=a[i]){ 37 q.pop(); 38 x++; 39 q.push(x); 40 } 41 else{ 42 ans++; 43 q.push(1); 44 } 45 } 46 printf("%d\n",ans); 47 return 0; 48 }
法二:
直接两个for循环查找,方法同样类似
找大于等于当前值
若小于当前值就再开一堆,即ans++
code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,ans,sum,maxn; 4 int a[500001]; 5 bool flag[500001]; 6 int main() 7 { 8 cin>>n; 9 for(int i=1;i<=n;i++) 10 cin>>a[i]; 11 sort(a+1,a+n+1); 12 maxn=a[n]; 13 for(int i=1;i<=n;i++) 14 if(!flag[i]) 15 { 16 ans++; 17 sum=0; 18 for(int k=i;k<=n;k++) 19 if(!flag[k]&&a[k]>=sum) 20 { 21 sum++; 22 flag[k]=true; 23 if(sum>maxn)break; 24 } 25 } 26 cout<<ans; 27 return 0; 28 }