HDU 6136 Death Podracing (堆)

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6136

题解

完了,普及题都不会做了。。。

发现一个重要性质是只有相邻的人才会相撞,于是直接拿堆维护即可。。。

WA了好几发。。。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
#define llong long long
using namespace std;

const int N = 1e5;
struct Fraction
{
    llong x,y;
    Fraction() {}
    Fraction(llong _x,llong _y) {x = _x,y = _y;}
    void output() {printf("%lld/%lld ",x,y);}
    bool operator <(const Fraction &arg) const
    {
        return x*arg.y<y*arg.x;
    }
};
struct Element
{
    llong a,b; int id;
    bool operator <(const Element &arg) const
    {
        return b<arg.b;
    }
} a[N+3];
struct Node
{
    int id1,id2; Fraction x;
    Node() {}
    Node(int _id1,int _id2,Fraction _x) {id1 = _id1,id2 = _id2,x = _x;}
    bool operator <(const Node &arg) const
    {
        return arg.x<x;
    }
};
priority_queue<Node> que;
bool vis[N+3];
int nxt[N+3],prv[N+3];
int n; llong m;

llong gcd(llong x,llong y) {return y==0 ? x : gcd(y,x%y);}

Fraction calc(Element x,Element y)
{
    if(x.a<y.a) {swap(x,y);}
    if(x.b>y.b) {y.b += m;}
    return Fraction(y.b-x.b,x.a-y.a);
}

int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d%lld",&n,&m);
        for(int i=1; i<=n; i++) scanf("%lld",&a[i].b);
        for(int i=1; i<=n; i++) scanf("%lld",&a[i].a),a[i].id = i;
        sort(a+1,a+n+1);
        for(int i=1; i<=n; i++) prv[i] = i==1?n:i-1,nxt[i] = i==n?1:i+1;
        for(int i=1; i<=n; i++) que.push(Node(i,nxt[i],calc(a[i],a[nxt[i]])));
        Fraction ans;
        while(!que.empty())
        {
            Node cur = que.top(); que.pop();
            int u = cur.id1,v = cur.id2;
            if(vis[u]||vis[v]) continue;
            ans = cur.x;
            if(a[u].id>a[nxt[u]].id) swap(u,v);
            vis[u] = true;
            if(prv[u]!=nxt[u])
            {
                que.push(Node(prv[u],nxt[u],calc(a[prv[u]],a[nxt[u]])));
            }
            nxt[prv[u]] = nxt[u];
            prv[nxt[u]] = prv[u];
        }
        llong g = gcd(ans.x,ans.y);
        printf("%lld/%lld\n",ans.x/g,ans.y/g);
        for(int i=1; i<=n; i++) vis[i] = nxt[i] = prv[i] = 0;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/suncongbo/p/11308225.html

时间: 2024-11-07 16:26:45

HDU 6136 Death Podracing (堆)的相关文章

hdu 6136 Death Podracing(模拟)

题目链接:hdu 6136 Death Podracing 题意: 有n个人在一个环形的跑道上,第i个人有一个power i,每个人有一个起始点和一个不同的速度. 如果两个人相遇,那么power大的那个人就会将power小的那个人淘汰出局. 然后问决出胜负需要多少时间. 题解: 显然,每次有人被淘汰出局的时候,都是被相邻的人干掉的,那么我们先预处理出相邻的人相遇的时间,然后扔进优先队列里面,每次选择最小的时间,将一个人淘汰掉,然后再更新一下当前的局势就行了. 1 #include<bits/st

HDU 6136 Death Podracing(循环链表)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6136 [题目大意] 一堆人在操场上跑步,他们都有一定的速度和初始位置, 当两个人相遇的时候编号较小的就会出局,当场上剩下最后一个人的时候游戏结束, 问时长为多少 [题解] 我们发现每次发生碰撞的一定是相邻的两个人, 所以我们找出相邻关系中最先发生碰撞的,将碰撞失败的那个人删除, 之后继续这个过程, 按照上述的做法我们建立一个循环链表,把所有人串起来, 当发生淘汰的时候把那个人从循环链表中删去即可

HDU 6136 Death Podracing

题意 给定长l的环上的n个人,每个人有给不相同的速度和位置,相遇时编号大的存活,问最后留存一个人时的时间 做法 直接用堆来模拟即可 #include <bits/stdc++.h> using namespace std; typedef long long LL; struct Frac { LL fz, fm; Frac() {} template<class T> Frac(T a):fz(a), fm(1) {} template<class T> Frac(T

hdu 2177 取(2堆)石子游戏

天资愚笨啊,网上的一大堆没看懂...... 总结百科的方法为: 1.a==b 同时减去a 得到0,0 2.a==a_k      b>b_k b -(b-b_k) 3.a==a_k     b<b_k 同时拿走a_k-a_(b-a_k) 得到 a_(b-a_k)    a_(b-a_k) + b-a_k 4.a>a_k       b==b_k 从a中拿走 a-a_k 5.a<a_k       b==b_k 5.1 a==a_ j   (j<k) b-(b-b_ j) 得到

HDU 2177 取(2堆)石子游戏 威佐夫博弈

题目来源:HDU 2177 取(2堆)石子游戏 题意:中文 思路:判断是否是必败态就不说了 做过hdu1527就知道了 现在如果不是必败态 输出下一步所有的必败态 题目要求先输出两堆都取的方案 首先 a = b 直接2堆取完 a != b 因为bi = ai+i 现在知道ak 和 bk 那么 k = bk-ak 得到k 求出 aj 和 bj 如果ak-aj == bk-bj && ak-aj > 0(aj, bj)是必败态 输出aj bj 然后是只取一堆的情况 假设a不变 求出对应的

HDU 2176 取(m堆)石子游戏 (尼姆博奕)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2176 m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取时可以从有8个的那一堆取走7个剩下1个,也可以从有9个的中那一堆取走9个剩下0个,也可以从有10个的中那一堆取走7个剩下3个. Input输入有多组.每组第1行是m,m<=200000. 后面m个非零正整数.m=0退出. Output先取

hdu 2176 取(m堆)石子游戏 (裸Nim)

题意: m堆石头,每堆石头个数:a[1]....a[m]. 每次只能在一堆里取,至少取一个. 最后没石子取者负. 先取者负输出NO,先取胜胜输出YES,然后输出先取者第1次取子的所有方法.如果从有a个石子的堆中取若干个后剩下b个后会胜就输出a b 思路: 裸的NIM. 单看一堆石子,没有石头sg[0]=0,一个石头sg[1]=1,....n个石头sg[n]=n. 故SG[a[1],a[2]...a[m]] = sg[a[1]]^...^sg[a[m]] = a[1]^...^a[m] SG=0

HDU 2176 取(m堆)石子游戏 博弈

取(m堆)石子游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3598    Accepted Submission(s): 2151 Problem Description m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取

HDU 1058 优先队列or堆

本来应当是一道优先队列或者堆的题 因为每个数都应该是已经得到的数*2 *3 *5 *7而得到的 但是 2*7 大于 3*2 这就必须保证每次取得都是没有拿过的最小的数 但是它主动降低难度在样例里卖了个萌 n的范围是1~5842 而第5842在样例里给出了..所以我们在取出一个数 求出它的*2 *3 *5 *7的时候做一下判断 如果大于最后一位就直接break 因为相乘的顺序在 可以省一点时间 在判断某个数是否出现过的时候 开不出那么大的vis数组 所以直接for循环从ans数组中寻找 所幸没有超