CF1065C Make It Equal (#树状数组)

题意翻译

有一个长度为nn的序列。

定义切割操作为把序列中所有大于等于HH(自定义)的数变为HH,定义其代价为操作前后序列中所有数的变化量的和。

定义一个“好的”切割操作为代价小于等于K的操作。

问至少需要多少次“好的”切割操作才可以使序列中的所有数的大小均相等。

题目描述

There is a toy building consisting of nn towers. Each tower consists of several cubes standing on each other. The ii -th tower consists of h_ihi​ cubes, so it has height h_ihi​ .

Let's define operation slice on some height HH as following: for each tower ii , if its height is greater than HH , then remove some top cubes to make tower's height equal to HH . Cost of one "slice" equals to the total number of removed cubes from all towers.

Let's name slice as good one if its cost is lower or equal to kk ( k \ge nk≥n ).

Calculate the minimum number of good slices you have to do to make all towers have the same height. Of course, it is always possible to make it so.

输入格式

The first line contains two integers nn and kk ( 1 \le n \le 2 \cdot 10^51≤n≤2⋅105 , n \le k \le 10^9n≤k≤109 ) — the number of towers and the restriction on slices, respectively.

The second line contains nn space separated integers h_1, h_2, \dots, h_nh1​,h2​,…,hn​ ( 1 \le h_i \le 2 \cdot 10^51≤hi​≤2⋅105 ) — the initial heights of towers.

输出格式

Print one integer — the minimum number of good slices you have to do to make all towers have the same heigth.

输入输出样例

输入 #1复制

5 5
3 1 2 2 4

输出 #1复制

2

输入 #2复制

4 5
2 3 4 5

输出 #2复制

2

说明/提示

In the first example it's optimal to make 22 slices. The first slice is on height 22 (its cost is 33 ), and the second one is on height 11 (its cost is 44 ).


思路

给一个数列,数列元素代表每个建筑的高度,然后水平一刀切下去,每次拿走的不能超过m个,然后要切多少次才能切平。

我们可以先处理每一个高度都有哪些建筑。切到最后,剩余的所有数都等于原序列中的最小值,所以原序列中的最小值minx+1到原序列中的最大值maxn这一段里面的箱子都是要切掉的,可以从上往下模拟。注意最后一次不要忘了切。

那么,如何处理每个高度有多少个建筑呢?可以用树状数组维护。

#include <stdio.h>
#include <iostream>
#define ll long long int
using namespace std;
ll bit[200001],a[200001],n,m,s,sum,maxn,minx(1e18+7);
inline ll lowbit(ll x)
{
	return x&-x;
}
inline void update(ll x,ll k)
{
	while(x<=maxn)
	{
		bit[x]+=k;
		x+=lowbit(x);
	}
}
inline ll query(ll x)
{
	register ll i(0);
	while(x>0)
	{
		i+=bit[x];
		x-=lowbit(x);
	}
	return i;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register ll i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		maxn=max(maxn,a[i]);
		minx=min(minx,a[i]);
	}
	for(i=1;i<=n;i++)
	{
		update(1,1);
		update(a[i]+1,-1);
	}//使区间[高度1,第i个建筑高度]都加上1 
	if(maxn==minx)//最大值和最小值相等一次都不用切。 
	{
		cout<<0<<endl;
		return 0;
	}
	bool f(1);
	for(i=maxn;i>=minx;i--)
	{
		j=query(i);//查询[1,i]的前缀和 
		if(j+sum>m)
		{
			s++;
			sum=j;
			f=0;
		}
		else
		{
			sum+=j;
			f=1;
		}
	}
	if(f) s++;
	cout<<s<<endl;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值