LOJ #2392. 「JOISC 2017 Day 1」烟花棒(贪心)
第一步二分答案。
注意其它人也是可以移动的,且其它人肯定往中间靠拢。
考虑不可能两个人同时拿着烟花跑,一个人跑(这个人跑完后再用新的烟花跑是一样的)是更优的,所以遇到一个人相当于时间加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);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址