题解 CF551C 【GukiZ hates Boxes】

这一道题目的考点为二分答案 + 模拟

二分答案我换成了是倍增,因为蒟蒻我怕二分答案写错(害怕二分写错的同学可以跟我一起写倍增啊)。

模拟的时候有一个技巧,就是每次记录一下当前所有物品中第一个没有被搬完的坐标点。
然后大力模拟。

这道题一定要开longlong,写倍增的时初始答案一定要足够大(最好开满longlong),我这里到了1e17才过。

Code:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int a[100005],b[100005];
long long ans = 10000110000000000;
int Tw[62] = {1} ;
int F[100005] , R = 0;
int pd(int x)
{
	int flag = 0,nxt = 1;
	for(int i = 1 ; i <= n ; i ++)
	{
		b[i] = a[i];
		if(b[i] == 0)flag ++;
	}
	for(int i = 1 ; i <= m && flag != n; i ++)
	{
		int life = x;
		life -= F[nxt];
		while(b[F[nxt]] <= life && life > 0 && flag < n)
		{
			flag ++,life -= b[F[nxt]],nxt ++;
			life -= (F[nxt] - F[nxt - 1]);
		}
		if(b[F[nxt]] > life && life > 0){
			b[F[nxt]] -= life;
			continue;
		}
	}
	if(flag == n)return 1;
	return 0;
}
void get_ans()
{
	for(int i = 62 ; i >= 0 ; i --)
		if(ans > Tw[i] && pd(ans - Tw[i]) != 0)ans -= Tw[i];
	cout << ans << endl;
}
signed main()
{
	cin >> n >> m;
	for(int i = 1 ; i <= n ; i ++)
	{
		cin >> a[i];
		if(a[i] != 0)R ++ , F[R] = i;
	}
	for(int i = 1 ; i <= 62 ; i ++)
		Tw[i] = Tw[i-1] << 1;
	get_ans();
	return 0;
}
原文地址:https://www.cnblogs.com/MYCui/p/13869886.html