C - Strange Radiation
題意:
你有一個炸彈,速度比人快。炸彈氣流從爆炸位置以速度s
向左右兩邊飛。
一維座標。給你n
個人的座標x
、走向dir
、速度v
。
當炸彈和人重疊且同向的時候,人的速度變爲v + s
,不考慮逆氣流的影響。
讓你在[0, 1e6]
的範圍內放置炸彈,花最少的時間使得至少有一個走到位置0
,還有一個人走到位置1e6
。求最少時間。
思路:
求最少時間。很容易想到二分結果求左界。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);
}