LOJ #2392. 「JOISC 2017 Day 1」烟花棒(贪心)

https://loj.ac/problem/2392

第一步二分答案。

注意其它人也是可以移动的,且其它人肯定往中间靠拢。

考虑不可能两个人同时拿着烟花跑,一个人跑(这个人跑完后再用新的烟花跑是一样的)是更优的,所以遇到一个人相当于时间加T。

问题变为:
有两个队列,每个队列有一些数,你需要从左往右选数,满足当前的时间一直\(\ge 0\),问是否可行。

和这题类似:
http://www.lydsy.com/JudgeOnline/problem.php?id=3709

考虑如果选了一个负数,那么就要一直选直到和\(\ge 0\),不然就不会选这个负数。

把每个队列缩成若干\((x,y)(y\ge 0)\):进来前要\(\ge x\),出去后加了\(y\),注意会剩下一些不能缩的。

先看,能不能把二元组做完,对于剩下的,考虑先加上它们,再倒过来做,问题等价。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 2e5 + 5;

ll n, k, T;
ll x[N];

#define db double

db a[N], b[N]; int a0, b0;
db c[N], d[N]; int c0, d0;

struct P {
	db x, y;
	P(db _x = 0, db _y = 0) {
		x = _x, y = _y;
	}
};

P p[N], q[N]; int p0, q0;

void build(db *a, int &a0, db *c, int &c0) {
	db s = 0; int la = 0;
	fo(i, 1, a0) {
		s += a[i];
		if(s >= 0) s = 0, la = i;
	}
	fd(i, a0, la + 1) c[++ c0] = -a[i];
	a0 = la;
}

void build(db *a, int &a0, P *p, int &p0) {
	db s = 0, mx = 0;
	fo(i, 1, a0) {
		s += a[i];
		mx = max(mx, -s);
		if(s >= 0) {
			p[++ p0] = P(mx, s);
			s = 0, mx = 0;
		}
	}
}

int work(db &z, P *p, int &p0, P *q, int &q0) {
	if(z < 0) return 0;
	int l = 1, r = 1;
	while(l <= p0 || r <= q0) {
		if(l <= p0 && z >= p[l].x) {
			z += p[l ++].y;
			continue;
		}
		if(r <= q0 && z >= q[r].x) {
			z += q[r ++].y;
			continue;
		}
		return 0;
	}
	return 1;
}

int pd(ll mi) {
	a0 = b0 = c0 = d0 = 0;
	fd(i, k - 1, 1) {
		a[++ a0] = (db) -(x[i + 1] - x[i]) / mi / 2;
		a[++ a0] = T;
	}
	fo(i, k + 1, n) {
		b[++ b0] = (db) -(x[i] - x[i - 1]) / mi / 2;
		b[++ b0] = T;
	}
	
	build(a, a0, c, c0);
	build(b, b0, d, d0);
	
	p0 = q0 = 0;
	build(a, a0, p, p0);
	build(b, b0, q, q0);
	
	db z = T;
	if(!work(z, p, p0, q, q0)) return 0;
	
	fo(i, 1, c0) z -= c[i];
	fo(i, 1, d0) z -= d[i];
	
	p0 = q0 = 0;
	
	build(c, c0, p, p0);
	build(d, d0, q, q0);
	
	return work(z, p, p0, q, q0);
}

int main() {
	scanf("%lld %lld %lld", &n, &k, &T);
	fo(i, 1, n) scanf("%lld", &x[i]);
	if(x[1] == x[n]) {
		pp("0\n"); return 0;
	}
	ll as = 0;
	for(ll l = 1, r = 1e18; l <= r; ) {
		ll m = l + r >> 1;
		if(pd(m)) as = m, r = m - 1; else l = m + 1;
	}
	pp("%lld\n", as);
}
posted @ 2020-05-26 21:23  Cold_Chair  阅读(486)  评论(0编辑  收藏  举报