题目:http://acm.hdu.edu.cn/showproblem.php?pid=6136
题意:在一个环上有n个人,每个人在不同的初始位置以及有不同的速度,每个人的武器强度为i,当相遇时武器强度弱的死亡,问比赛结束时的时间
看了题解还是写了很久 开始自己维护的太复杂 实际上只需要维护左右是谁就行了
官方题解 :
解法一
第一种解法比较直观,最初始状态环上有 nnn 个人,第一次淘汰发生必然是环上相邻的两个人相撞。注意到第一个被淘汰的人不会对后续过程有任何影响,如果我们能找出谁是第一个被淘汰的,直接把这个人从初始状态中删除,就能把问题变成一个只有 n−1n-1n−1 个人的子问题,这个子问题和原问题有相同的答案。
于是我们可以用一个堆维护环上所有相邻人相遇的时间,从中取出最小值,就能找到第一个被淘汰的人,这个人删除后,原本不相邻的两个人就相邻了,同样求出他们的相遇时间,加入堆中,重复执行这一过程,直到找到最后一个被淘汰的人为止。算法复杂度 O(nlogn)
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #define lson i<<1 #define rson i<<1|1 using namespace std; const int N=2e5+5; int d[N],v[N],l[N],r[N]; bool use[N]; int n,len; struct people { int d,v,num; bool operator <(const people&tem) const { return d<tem.d; } }a[N]; struct p { int x,y; double t; p(int xx=0,int yy=0) { x=xx;y=yy; if (x>y) { if (a[x].v>a[y].v) t=(len-abs(a[y].d-a[x].d))*1.0/(abs(a[y].v-a[x].v)*1.0); else t=abs(a[y].d-a[x].d)*1.0/(abs(a[y].v-a[x].v)*1.0); } else { if (a[y].v>a[x].v) t=(len-abs(a[y].d-a[x].d))*1.0/(abs(a[y].v-a[x].v)*1.0); else t=abs(a[y].d-a[x].d)*1.0/(abs(a[y].v-a[x].v)*1.0); } } bool operator <(const p&tem) const { return t>tem.t; } }; int gcd(int x,int y) { if (x<y) swap(x,y); int t; while(y) { t=x%y; x=y; y=t; } return x; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&len); for(int i=1;i<=n;i++) { scanf("%d",&a[i].d); a[i].num=i; } for(int i=1;i<=n;i++) scanf("%d",&a[i].v); sort(a+1,a+1+n); priority_queue<p> que; for(int i=1;i<=n;i++) { que.push(p(i,i+1>n?1:i+1)); l[i]=i-1<1?n:i-1; r[i]=i+1>n?1:i+1; } memset(use,0,sizeof(use)); int sz=n-1; int x,y; while(!que.empty()) { p t=que.top();que.pop(); if (use[t.x]||use[t.y]) continue; if (a[t.x].num<a[t.y].num) { use[t.x]=1; l[t.y]=l[t.x];r[l[t.x]]=t.y; que.push(p(l[t.x],t.y)); } else { use[t.y]=1; r[t.x]=r[t.y];l[r[t.y]]=t.x; que.push(p(t.x,r[t.y])); } sz--; if (sz==0) { x=t.x;y=t.y; break; } } int t1=abs(a[x].d-a[y].d); int t2=abs(a[x].v-a[y].v); if ((x>y&&a[x].v>a[y].v)||(x<y&&a[y].v>a[x].v)) t1=len-t1; int tt=gcd(t1,t2); t1/=tt;t2/=tt; printf("%d/%d ",t1,t2); } return 0; }