可以考虑维护一个数组chao(超),chao[i]表示高度超过i的有几块砖。后强行模拟删砖的步骤即可。又因为其中由于涉及到了区间加减,可考虑用线段树进行维护。
附AC Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,a[N],maxx=-0x3f3f3f3f,minn=0x3f3f3f3f,k,chao[N],biaoji[N],c[N];
struct SegmentTree{
int l,r;
int add,data;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define add(x) tree[x].add
#define data(x) tree[x].data
}tree[N*4];
inline void build(int p,int l,int r){
l(p)=l,r(p)=r;
if(l==r){
data(p)=chao[l];
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
data(p)=data(p<<1)+data(p<<1|1);
}
inline void spread(int x){
if(add(x)){
data(x<<1)+=add(x)*(r(x<<1)-l(x<<1)+1);
data(x<<1|1)+=add(x)*(r(x<<1|1)-l(x<<1|1)+1);
add(x<<1)+=add(x);
add(x<<1|1)+=add(x);
add(x)=0;
}
}
inline void change(int p,int l,int r,int d){
if(l(p)>=l && r(p)<=r){
data(p)+=d*(r(p)-l(p)+1);
add(p)+=d;
return;
}
spread(p);
int mid=l(p)+r(p)>>1;
if(l<=mid) change(p<<1,l,r,d);
if(r>mid) change(p<<1|1,l,r,d);
data(p)=data(p<<1)+data(p<<1|1);
}
inline int query(int p,int l,int r){
if(l(p)>=l&&r(p)<=r) return data(p);
spread(p);
int mid=l(p)+r(p)>>1,val=0;
if(l<=mid) val+=query(p<<1,l,r);
if(r> mid) val+=query(p<<1|1,l,r);
return val;
}
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
maxx=max(maxx,a[i]),minn=min(minn,a[i]);
}
sort(a+1,a+n+1);
int ans=0;
if(a[1]==a[n]){
puts("0");
return 0;
}
for(int i=1;i<=n;i++) biaoji[a[i]]++;
int lst=-1,tmp=-1,cnt=0;
for(int i=maxx;i>=0;i--){
if(biaoji[i]){
if(lst!=-1) chao[i]=chao[lst]+(lst-i)*cnt;
tmp=biaoji[i];
lst=i;
cnt+=biaoji[i];
}
else chao[i]=chao[lst]+(lst-i)*cnt;
}
build(1,0,maxx);
bool flag=true;
for(int i=maxx;i>=minn;i--){
if(query(1,i,i)<=k && query(1,i-1,i-1)>k){
ans++;
flag=false;
change(1,0,i,-1*query(1,i,i));
}
else flag=true;
}
cout<<ans+flag<<endl;
return 0;
}