难受的很......比赛时候写出来正解高兴得不得了结果少了特判被hack+fst了.......难受
题意:
给定N个由高度相同的方块摞起来的塔,一次操作能将高度在某个值以上的方块全部消除,代价为消去的方块数量。
规定每次操作代价不能超过给定的K,求至少经过多少次操作才能将所有塔的高度变得相同。
题解:
首先把所有塔的高度减去其中的最小值,问题就变成了将塔消完所需要的步数。
然后维护一个前缀和数组 $ b $ , $ b[i] $ 表示有多少塔的高度(削过之后)大于 $ i $ 。
或者可以理解为:在高度为 $ i $ 处有多少方块。
这样我们就得到了一个一维数组b。
由于每次操作都会消去一层或多层内所有方块,所以可以将数组b理解为「一层一层消,每次所需要的代价」。
接下来所要做的就是合并这些代价,使合并后每段的和都不超过给定的k。
合并后有几段,就是需要操作多少次。
注意特判
· 如果只有一个塔,那么直接输出0.
· 如果所有塔高度相同,那么直接输出0.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
LL n,k;
int a[200050];
bool cmp(int x,int y){
return x>y;
}
int minn=2147483647,maxn=0;
int b[200050];
int main(){
scanf("%lld%lld",&n,&k);
for(int i(1);i<=n;i++)scanf("%d",&a[i]),minn=min(minn,a[i]),maxn=max(maxn,a[i]);
if(n==1){
cout<<0;
return 0;
}
for(int i(1);i<=n;i++){
a[i]-=minn;
b[1]++;
b[a[i]+1]--;
}
for(int i(2);i<=n;i++){
if(a[i]!=a[1])break;
if(i==n){
cout<<0;
return 0;
}
}
for(int i(2);i<=maxn;i++)b[i]+=b[i-1];
int tmp=0,ans=1;
for(int i(1);i<=maxn;i++){
if(tmp+b[i]<=k)tmp+=b[i];
else ans++,tmp=b[i];
}
printf("%d",ans);
return 0;
}