POJ2274[The Race]题解
来源:互联网 发布:linux 窗口编程 编辑:程序博客网 时间:2024/06/06 00:59
题目概述
给出n(n<=250000)辆赛车,i赛车初始在xi,速度为vi,赛车在比赛时会发生超车(不会相撞)。求超车次数%1000000,并输出前10000次(不足10000次有几次输出几次)超车,格式为x y,表示x超过y,时间靠前的先输出,时间相同位置靠前的先输出,保证没有时间相同位置也相同的超车。
解题报告
第一问显然就是逆序对,用二路归并求解即可。关键就是这个第二问难,好像除了O(n^2)的扫描没有办法。
如果总体来看,非常难处理,我们要把总体的问题尽量缩小,才能方便的处理:对于超车,肯定是相邻两个先超车(超车完之后相邻位置就改了)。有了这个思路,我们可以刚开始相邻算出超车时间,然后从中挑出一个小的,这就是第一次超车,超车完毕之后,因为相邻位置交换,所以要重新对左右两个车进行计算(利用链表就可以快速找到相邻位置),算出新的超车时间,然后又挑出一个小的,重新计算……
每次挑出小的,让我们想到了堆,至此,这道题就解完了。下面给出示意图:
示例程序
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=250000,tt=1000000;struct Car{ int x,v; bool operator <= (const Car &a) const {return v<=a.v;}}; //赛车的结构体struct Heap{ int x,y; double ti,dis; bool operator < (const Heap &a) const {return ti<a.ti||ti==a.ti&&dis<a.dis;}}; //堆的结构体int n,len_s,ans,l[maxn+5],r[maxn+5]; //l[i]表示i的左边,r[i]表示i的右边Car a[maxn+5],b[maxn+5],c[maxn+5];Heap heap_s[maxn+10000+5]; //因为最多做10000次,每次最多会增加一个,所以要开maxn+10000bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}int readi(int &x) //读入优化{ int tot=0,f=1; char ch=getchar();if (ch==EOF) return EOF; while ('9'<ch||ch<'0') {if (ch=='-') f=-f;ch=getchar();} while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=getchar(); x=tot*f; return Eoln(ch);}void msort(int L,int R) //二路归并{ if (L>=R) return;int mid=L+(R-L>>1); msort(L,mid);msort(mid+1,R); for (int k=L;k<=R;k++) c[k]=b[k]; int i=L,j=mid+1; for (int k=L;k<=R;k++) if (j>R||i<=mid&&c[i]<=c[j]) b[k]=c[i++]; else b[k]=c[j++],ans=(ans+mid-i+1)%tt;}void put_s(int x,int y,double ti,double dis) //放入堆中{ int son;heap_s[++len_s]=(Heap){x,y,ti,dis};son=len_s; while (son!=1&&heap_s[son]<heap_s[son>>1]) { swap(heap_s[son],heap_s[son>>1]); son>>=1; }}void del_s() //删除堆顶{ int fa=1,son;heap_s[1]=heap_s[len_s--]; while (2*fa<=len_s) { if (2*fa+1>len_s||heap_s[2*fa]<heap_s[2*fa+1]) son=2*fa; else son=2*fa+1; if (heap_s[son]<heap_s[fa]) { swap(heap_s[son],heap_s[fa]); fa=son; } else break; }}double getti(int i,int j) {return (double)(a[j].x-a[i].x)/(a[i].v-a[j].v);} //得到i和j相遇的时间double getdis(int i,int j) {return a[i].x+getti(i,j)*a[i].v;} //得到i和j相遇的位置int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); readi(n); for (int i=1;i<=n;i++) readi(a[i].x),readi(a[i].v); memcpy(b,a,sizeof(b)); //备份一个b用来二路归并求逆序对 msort(1,n); printf("%d\n",ans); for (int i=1;i<=n;i++) l[i]=i-1,r[i]=i+1; for (int i=1;i<=n-1;i++) if (a[i].v>a[i+1].v) put_s(i,i+1,getti(i,i+1),getdis(i,i+1)); //相邻建边,加入堆中 int te=1; while (len_s&&te<=10000) { int x=heap_s[1].x,y=heap_s[1].y,lx=l[x],ry=r[y];del_s(); //得到堆顶 if (r[x]!=y||l[y]!=x) continue; //判断该堆顶是否“过期”,也就是判重 printf("%d %d\n",x,y);te++; if (ry!=n+1) {l[ry]=x;if (a[x].v>a[ry].v) put_s(x,ry,getti(x,ry),getdis(x,ry));} //x和y交换过后,x和r[y]产生新状况 if (lx) {r[lx]=y;if (a[lx].v>a[y].v) put_s(lx,y,getti(lx,y),getdis(lx,y));} //x和y交换后,y和l[x]产生新状况 l[x]=y;r[y]=x;r[x]=ry;l[y]=lx; //修正链表 } return 0;}
2 0
- POJ2274[The Race]题解
- POJ2274【CEOI2003】The Race
- Poj2274[The Race]题解--逆序对&二叉堆
- POJ2274——The Race
- Day at the Race
- usaco training 4.3.3 Street Race 题解
- 【BZOJ】【P2599】【IOI2011】【Race】【题解】【点分治】
- BZOJ 2599: [IOI2011]Race 点分治题解
- Lesson 69 The car race.
- poj 2274 The Race 小根堆
- [poj 2274] The Race 堆
- Race
- Codeforces 48C The Race 模拟题
- codeforces #328 C. The Big Race
- POJ 2274 [The Race]【堆+链表】
- Codeforces Round #438 B. Race Against Time 题解
- poj 2274 The Race(逆序数+线段树)
- MultiRace-Efficient on-the-fly data race detection
- 2017-过年
- 详解Spring事件驱动模型
- mysql 数据库 优化
- 0、题目分类
- 圆的面积
- POJ2274[The Race]题解
- 2757:最长上升子序列
- 【t018】派对
- C++工程师面试宝典系列之多线程编程
- 存储进程输出 Queue
- jQuery总结(二)
- 关于swing_table添加双击事件监听器
- 【SCU4436】【数学归纳】【二分】Easy Math题解
- Java面试题