HDU-6135 Casual Podracing(CDQ分治)

传送门: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值