传送门:HDU-6135
题意:一个长度为L的圈,有n个人在上面跑,每个人的起始位置为di,速度为vi,且起始位置和速度均不相同,每个人有力量值wi,如果一个人遇到力量值比自己大的,则这个人会被标记,直到不会有人再被标记时将会停止,问这个过程总共花费多少时间
题解:CDQ分治
设2个人的起始位置为d1和d2,d1<d2,设时间为t,如果这2个人相遇,则一定会有d1+t*v1>=t2+t*v2或d1+t*v1<=t2+t*v2-L
因此可以二分时间,记录时间t下每个人跑的距离dir[i],按照起始位置从小到大排序,分治时按照力量值w从大到小排序,归并时记录左右两边d+t*v的最小值L1,L2和最大值R1,R2。对于左分治区间[l,m]的每个人,如果dir[i]>=L2或dir[i]<=R2-L则将它标记;对于右分治区间[m+1,r]的每个人,如果dir[j]>=L1+L或dir[j]<=R1则将它标记;如果存在人的力量值不是最大的且这个人没有被标记,则返回false,并记录他为最后一个要被标记的人last
由于题目比较毒瘤,要求输出的是分数形式,因此就要用到last,因为last是最后一个被标记的人,因此只要找到最先标记他的那个人,然后记录一下他们的距离和速度差即可。
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const double eps = 1e-7;
const double inf = 1e20;
const int MX = 1e5 + 5;
struct node {
int d, v, w, id;
double dir;
} p[MX], np[MX], tmp[MX];
int n, L, vis[MX];
void solve(int l, int r) {
if (l >= r) return;
int m = (l + r) >> 1;
solve(l, m); solve(m + 1, r);
int p1 = l, p2 = m + 1, p3 = l;
double TL1 = inf, TL2 = inf, TR1 = -inf, TR2 = -inf;
double L1 = inf, L2 = inf, R1 = -inf, R2 = -inf;
while (p1 <= m || p2 <= r) {
if (p2 > r || (p1 <= m && np[p1].w > np[p2].w)) {
if (p3 > l && tmp[p3 - 1].w > np[p1].w) {
L1 = TL1; R1 = TR1;
L2 = TL2; R2 = TR2;
}
if (L2 <= np[p1].dir || R2 - L >= np[p1].dir) vis[np[p1].id] = 1;
TL1 = min(TL1, np[p1].dir);
TR1 = max(TR1, np[p1].dir);
tmp[p3++] = np[p1++];
} else {
if (p3 > l && tmp[p3 - 1].w > np[p2].w) {
L1 = TL1; R1 = TR1;
L2 = TL2; R2 = TR2;
}
if (L1 + L <= np[p2].dir || R1 >= np[p2].dir) vis[np[p2].id] = 1;
TL2 = min(TL2, np[p2].dir);
TR2 = max(TR2, np[p2].dir);
tmp[p3++] = np[p2++];
}
}
for (int i = l; i <= r; i++) np[i] = tmp[i];
}
int last, mx;
bool ok(double t) {
for (int i = 1; i <= n; i++) {
np[i] = p[i], vis[i] = 0;
np[i].dir = np[i].d + t * np[i].v;
}
solve(1, n);
for (int i = 1; i <= n; i++)
if (vis[i] == 0 && p[i].w != mx) {
last = i; //最后一个被标记的
return 0;
}
return 1;
}
bool cmp(node p1, node p2) {
return p1.d < p2.d;
}
void update(node p1, node p2, int &dx, int &dy) {
if (p1.v < p2.v) swap(p1, p2);
LL x = p1.v - p2.v, y;
if (p1.d < p2.d) y = p2.d - p1.d;
else y = L - p1.d + p2.d;
if (y * dx <= x * dy) dy = y, dx = x;
}
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &L);
for (int i = 1; i <= n; i++) scanf("%d", &p[i].d);
for (int i = 1; i <= n; i++) scanf("%d", &p[i].v);
for (int i = 1; i <= n; i++) scanf("%d", &p[i].w);
sort(p + 1, p + n + 1, cmp);
mx = 0;
for (int i = 1; i <= n; i++) {
p[i].id = i;
if (mx < p[i].w) mx = p[i].w;
}
double l = 0, r = L;
last = 0;
while (l < r - eps) {
double m = (l + r) / 2;
if (ok(m)) r = m;
else l = m;
}
if (!last) printf("0\n");
else {
int dx = 0, dy = 0;
for (int i = 1; i <= n; i++) if (p[i].w > p[last].w) update(p[i], p[last], dx, dy);
printf("%d/%d\n", dy / __gcd(dx, dy), dx / __gcd(dx, dy));
}
}
return 0;
}