ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

loj2392. 「JOISC 2017 Day 1」烟花棒

2019-07-17 21:53:36  阅读:296  来源: 互联网

标签:loj2392 geq int 点燃 烟花 JOISC && 区间 2017


题意

题目说的很清楚了亚。。把题面再复制一遍吧。

有\(N\)人站在一条数轴上。他们人手一个烟花,每人手中的烟花都恰好能燃烧\(T\)秒。每个烟花只能被点燃一次。
\(1\)号站在原点,\(i\)号(\(1 \leq i \leq N\))到\(1\)号的距离为\(X_i\)。保证\(X_1 = 0\),\(X_1, X_2, ..., X_N\)单调递增(可能有人位置重叠)。
开始时,\(K\)号的烟花刚开始燃烧,其他人的烟花均未点燃。他们的点火工具坏了,只能用燃着的烟花将未点燃的烟花点燃。当两人位置重叠且其中一人手中的烟花燃着时,另一人手中的烟花就可以被点燃。忽略点火所需时间。
求至少需要以多快的速度跑,才能点燃所有人的烟花(此时可能有些人的烟花已经熄灭了)。速度必须是一个非负整数。

note:所求的速度为全程中最大速度的最小值。

题解

本题满足二分性质,我们可以二分一个所求\(v\),然后判断是否有合法方案。

注意到对于一个区间\([L, R]\),且区间中起初有一个烟花是燃烧的,如果可以点燃区间中所有烟花,其中一种方案一定满足,所有人的相对位置不发生改变。因此,在这种方案中,只要满足\(x_L + vT(R - L) \geq x_R - vT(R - L)\)即可。而同样,如果不满足\(x_L + vT(R - L) \geq x_R - vT(R - L)\)这个条件,那么显然整个区间是不能被全部点燃的(以\(v\)的速度)。

观察上面的柿子,移项,得
\[ x_L - 2vTL \geq x_R - 2vTR \]
则令\(a_i = x_i - 2vTi\),则问题变为从区间\([K, K]\)开始向外扩展区间,要保证每个时刻扩展出的区间\([l, r]\)要满足\(a_l \geq a_r\)。当且仅当能扩展到区间\([1, n]\),所有烟花可以被点燃。

观察一个性质:对于可扩展区间\([l, r]\),对于\(i < l\),如果满足:

1.\(a_i \geq a_l\)

2.\(\forall j \in [i, l]\),\(a_j \geq a_r\)

则可知区间\([i, r]\)也是可以扩展的。

就这样,我们可以左右不断做这个操作,每次固定合法区间左(右)端点,向外移动右(左)端点。

如果某次向左向右都无法扩展了,且是因为\(a_i \geq a_l \wedge \exists j \in [i, l], a_j < a_r\)这样的原因,那么说明无法点燃整个大区间\([1, n]\)的烟花。

否则,我们会得到一个极大的区间\([ml, mr]\)(这个区间不能通过上述的方式扩展,且是因为\(\nexists i < l, a_i \geq a_l\))。

这时,我们只能换一种方式来判断——从整个大区间\([1, n]\)向内缩。

此时,对于可缩区间\([l, r]\),对于\(l < i \leq ml\),如果满足:

1.\(a_i \geq a_l\)

2.\(\forall j \in [l, i]\),\(a_j \geq a_r\)

区间\([i, r]\)也可以缩得。

直到区间\([ml, mr]\)如果可以缩得,那么就说明可以点燃所有烟花。

证明?其实这是一个逆向过程,把过程逆一下就挺显然的了。(可以画个折线图试试)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, K, T, x[N];
ll a[N];

bool check (int v) {
    for (int i = 1; i <= n; ++i) {
        a[i] = 0ll + x[i] - 2ll * T * v * i;
    }
    if (a[1] < a[n]) {
        return 0;
    }
    int ql = K, qr = K, l, r;
    for (int i = K - 1; i; --i) {
        if (a[i] >= a[ql]) {
            ql = i;
        }
    }
    for (int i = K + 1; i <= n; ++i) {
        if (a[i] <= a[qr]) {
            qr = i;
        }
    }
    for (l = r = K; l != ql || r != qr; ) {
        int ok = 0, L = l, R = r;
        for ( ; L > ql && a[L - 1] >= a[r]; ) {
            if (a[--L] >= a[l]) {
                break;
            }
        }
        if (L < l && a[L] >= a[l]) {
            ok = 1, l = L;
        }
        for ( ; R < qr && a[R + 1] <= a[l]; ) {
            if (a[++R] <= a[r]) {
                break;
            }
        }
        if (R > r && a[R] <= a[r]) {
            ok = 1, r = R;
        }
        if (!ok) {
            return 0;
        }
    }
    for (l = 1, r = n; l != ql || r != qr; ) {
        int ok = 0, L = l, R = r;
        for ( ; L < ql && a[L + 1] >= a[r]; ) {
            if (a[++L] >= a[l]) {
                break;
            }
        }
        if (L > l && a[L] >= a[l]) {
            ok = 1, l = L;
        }
        for ( ; R > qr && a[R - 1] <= a[l]; ) {
            if (a[--R] <= a[r]) {
                break;
            }
        }
        if (R < r && a[R] <= a[r]) {
            ok = 1, r = R;
        }
        if (!ok) {
            return 0;
        }
    }
    return 1;
}
int main () {
    scanf("%d%d%d", &n, &K, &T);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &x[i]);
    }
    int l = 0, r = 1e9, mid, ans = r;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (check(mid)) {
            ans = mid;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    printf("%d\n", ans);
    return 0;
}

标签:loj2392,geq,int,点燃,烟花,JOISC,&&,区间,2017
来源: https://www.cnblogs.com/psimonw/p/11203634.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有