The 2018 ACM-ICPC Asia Qingdao Regional Contest E Plants vs. Zombies(ZOJ 4062)

本文深入解析了一道ACM竞赛题目,通过二分查找法解决最大化最小价值的问题,详细介绍了算法思路与实现代码,包括check函数的具体设计和细节处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ProLink:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4062

题意:有一列n个土地,每个土地经过会增长a[i]的价值,你可以走m步,让你最大化最小值

解题思路:最大化最小值,显然就是二分了,最大1e17,最小0,直接二分答案就行了

这题主要是check不好写。。

考虑一下check函数:对于一块地,肯定就是左右一直移动来让他的价值>=当前check的x,一直这样做下去。不过小细节有点多,我开了一个cnt数组直接来记录每块地达到这个值需要的最小次数,循环的时候标记一个flag,作用是判断当前这个点,要不要来回移动(因为肯定有一些点至于要一次,来回反而浪费了),还有,如果当前检查的时候ret就已经大于m +1了(至于为什么不是大于m,至于为什么要边跑边判,自己想),最后就是循环完了看一下最后一个的值,细节真的多。

Code:

#pragma GCC diagnostic error "-std=c++11"
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<ext/rope>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define gcd __gcd
#define pb push_back
#define mp anske_pair
#define lowbit(x) x & (-x)
#define PII  pair<int, int> 
#define all(x) x.begin(), x.end()
#define rep(i, a, b) for(__typeof(b) i = a; i <= (b); i++)
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
using __gnu_cxx::crope;

ll n, m;
int a[maxn];
ll cnt[maxn];

bool check(ll x){
	ll ret = 0;
	rep(i, 1, n + 1) cnt[i] = 0;
	rep(i, 1, n){
		cnt[i] = x / a[i];
		if(x % a[i]) cnt[i]++;
	}
	bool flag = false;
	rep(i, 1, n){
		if(cnt[i] > 0){
			ret += cnt[i] * 2;
			cnt[i+1] -= cnt[i];
			cnt[i] = 0;
			if(!flag) flag = true;
			else ret++, cnt[i+1]--;
		}
		else flag = false;
		if(ret > m + 1) return false;
	}
	if(cnt[n+1]) ret--;
	if(cnt[n] < 0) ret--;
	if(ret <= m) return true;
	return false;
}

int main()
{
	int t; scanf("%d", &t);
	while(t--){
		scanf("%lld %lld", &n, &m);
		rep(i, 1, n) scanf("%d", a + i);
		if(n > m) { puts("0"); continue; }
		ll l = 0, r = (ll)1e18;
		ll ans;
		while(l <= r){
			ll mid = (l + r) >> 1ll;
			//cout << mid << endl;
			if(check(mid)){
				l = mid + 1;
				ans = mid;
			}
			else{
				r = mid - 1;
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值