Codeforces Round #425 (Div. 2) C - Strange Radiation【二分、數學、前綴和】

C - Strange Radiation

題意:

你有一個炸彈,速度比人快。炸彈氣流從爆炸位置以速度s向左右兩邊飛。
一維座標。給你n個人的座標x走向dir速度v
當炸彈和人重疊且同向的時候,人的速度變爲v + s,不考慮逆氣流的影響。
讓你在[0, 1e6]的範圍內放置炸彈,花最少的時間使得至少有一個走到位置0,還有一個人走到位置1e6。求最少時間。

思路:

求最少時間。很容易想到二分結果求左界。judge函數的推導如下(以向左走爲例):
judge函數中的判斷條件

三個式子化簡後可以得到往左走的條件爲:
這裏寫圖片描述
同理可以得到,往右走的條件爲:
這裏寫圖片描述
統計所有人的區間並,然後當向左走的和向右走的區間存在交集,那就表示當前時間可行,返回true。
注意:
1)注意處理無效數據,即x的左邊大於右邊的情況。
2)通過累計前綴和的方法判斷區間是否有交集。

代碼:

#include <bits/stdc++.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
const int maxn = 1e6;
int n, s;
struct Node {
    int x, v, dir;
}node[maxn + 10];
int lef[maxn + 10], rigt[maxn + 10];
bool judge(double t) {
    memset(lef, 0, sizeof(lef));
    memset(rigt, 0, sizeof(rigt));
    for(int i = 1; i <= n; ++ i) {
        if(node[i].dir == 1) {
            if(1.0 * node[i].x / node[i].v <= t) {
                lef[0]++;
                continue;
            }
            //推算的公式,計算t時間下,放的炸彈的位置
            LL dis = floor( (1.0 * t * (node[i].v + s) - node[i].x) * (s - node[i].v) / s + node[i].x ); //向下取整
            //只有dis >= node[i].x纔有意義
            if(dis >= node[i].x) {
                dis = min(dis, 1e6);//>=node[i].x的位置隨意放, 防止數組越界
                lef[node[i].x]++;
                lef[dis + 1]--;
            }

        } else {
            double d = 1.0 * 1e6 - node[i].x;
            if(1.0 * d / node[i].v <= t) {
                rigt[0]++;
                continue;
            }
            //推算的公式,計算t時間下,放的炸彈的位置
            LL dis = ceil( 1.0 * node[i].x - (t * (node[i].v + s) + node[i].x - 1e6) * (s - node[i].v) / s ); //向上取整
            //只有dis >= node[i].x纔有意義
            if(dis <= node[i].x) {
                dis = max(dis, 0); // <= node[i].x的位置隨意放,防止數組越界
                rigt[dis]++;
                rigt[node[i].x + 1]--;
            }
        }
    }
    //求前綴和,判斷是否區間有重疊
    for(int i = 1; i <= 1e6; ++ i) {
        lef[i] += lef[i-1];
        rigt[i] += rigt[i-1];
    }
    for(int i = 0; i <= 1e6; ++ i) {
        if(lef[i] && rigt[i]) return true;
    }
    return false;
}
int main() {
    scanf("%d%d", &n, &s);
    for(int i = 1; i <= n; ++ i) {
        scanf("%d%d%d", &node[i].x, &node[i].v, &node[i].dir);
    }
    double low = 0, high = 1e6 + 5;
    for(int cas = 0; cas < 100; ++ cas) {
        double mid = (low + high) / 2;
        if(judge(mid)) high = mid;
        else low = mid;
    }
    printf("%.7f\n", low);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章