poj 2274 The Race 最小堆
2016-06-15 23:45
281 查看
题目链接
题目大意:
给n个小车, 每个小车有一个初始位置x和初始速度v, 保证x1 < x2..... <xn。 0<v<100。然后问你一共会发生多少次超车, 以及前10000次超车分别是哪两辆车, 按超车的时间顺序给出。
思路:
第一问显然就是一个逆序数, 因为v<100, 所以暴力统计就可以了。第二问, 我们通过观察可以得出一个性质, 超车总是先发生在相邻的两辆车。
比如a, b, c三个车, 如果他们的速度是va > vc > vb, 那么超车肯定是a超过b, 然后才能超过c。 a不可能直接不通过b就超过c。
有了这个性质, 我们可以先将所有相邻的可能发生的超车情况放入一个优先队列。 队列里的元素有4个值, 超车的时间, 超车发生的坐标, 超车的两辆车的编号。
然后初始的时候记录一下每个车前面的车的坐标以及后面的坐标。 初始就是i-1和i+1。
然后如果发生超车, 比如初始是 1, 2, 3, 4。 然后2超过3, 变成1, 3, 2, 4。 每辆车的前后坐标也要改变。 初始pre[2] = 1, nxt[2] = 3,超车之后变成pre[2] = 3, nxt[2] = 4。大概就是这样。 同时1, 3, 4也都会发生改变。
然后每次超车之后, 在将新的可能发生的超车加入队列。 然后这么不断循环。直到队列空或者10000个。
还有一种就是 a, b, c 三个车, va > vb > vc, 然后初始将a超过b, b超过c的情况放入了队列, 这时候b超过了c, 然后将a超过c的情况放入队列。然后a超过c, 再次将a超过b的情况放入队列。如果不判断一下的话就会将a超过b的情况计算两次。 判断的方法, 我是这样的。 比如两辆车a,b。 看nxt[a]是否等于b以及pre[b] 是否等于a, 如果不等于直接continue。
具体的可以看看代码自己想一下... 真是写了好久。
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <complex> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define mem(a) memset(a, 0, sizeof(a)) #define fi first #define se second typedef pair<int, int> pll; const double eps = 1e-8; const int maxn = 250005; int cnt[100], pre[maxn], nxt[maxn]; double v[maxn], x[maxn]; struct node { double t, pos; int car1, car2; node(){} node(double t, double pos, int car1, int car2):t(t), pos(pos), car1(car1), car2(car2){} bool operator < (node a) const { if(fabs(t - a.t)<eps) { return pos > a.pos; } return t > a.t; } }; vector <pll> ans; int main() { int n; while(cin>>n) { priority_queue <node> q; ans.clear(); mem(cnt); mem(pre); mem(nxt); int sum = 0; for(int i = 1; i <= n; i++) { scanf("%lf%lf", &x[i], &v[i]); nxt[i] = i+1; pre[i] = i-1; cnt[(int)v[i]]++; for(int j = v[i]+1; j < 100; j++) { sum += cnt[j]; sum %= 1000000; } } for(int i = 1; i < n; i++) { if(v[i] > v[i+1]) { double t = 1.0*(x[i+1]-x[i])/(v[i]-v[i+1]); q.push(node(t, t*v[i]+x[i], i, i+1)); } } int num = 10000; while(num && !q.empty()) { node tmp = q.top(); q.pop(); int fi = tmp.car1, se = tmp.car2; if(nxt[fi] != se || pre[se] != fi) continue; ans.pb(mk(fi, se)); nxt[fi] = nxt[se]; pre[se] = pre[fi]; nxt[se] = fi; pre[fi] = se; nxt[pre[se]] = se; pre[nxt[fi]] = fi; if(pre[se] && v[pre[se]] > v[se]) { double t = (tmp.pos - v[pre[se]]*tmp.t-x[pre[se]])/(v[pre[se]] - v[se]); q.push(node(tmp.t + t, tmp.pos + v[se]*t, pre[se], se)); } if(nxt[fi] != n+1 && v[fi] > v[nxt[fi]]) { double t = 1.0*(x[nxt[fi]] + v[nxt[fi]]*tmp.t - tmp.pos)/(v[fi] - v[nxt[fi]]); q.push(node(tmp.t+t, tmp.pos + v[fi]*t, fi, nxt[fi])); } num--; } cout<<sum<<endl; for(int i = 0; i < ans.size(); i++) { printf("%d %d\n", ans[i].fi, ans[i].se); } } return 0; }
相关文章推荐
- BIOS—>Kernel
- uboot初学
- Occam剃刀原理及过拟合问题
- Http状态码
- C++第三次作业(补)
- 【Java】static关键字
- android安装前期遇到的问题
- c#3.0新特性
- 用双向链表实现一个栈和队列
- content provider使用大总结
- mybatis3.0 配置等值连接两种方式:resultMap和resulttype
- Python基础(十)re模块
- Objective-C中遍历字典、数组和集合的几种常见方式
- 【Git】相关
- Postman发送带cookie的http请求
- <Sicily>Pythagorean Proposition
- JavaScript 的 Date 方法的使用
- 从数据库中读取表中数据然后写到txt文件中
- MyBatis-输入输出包装
- Wrangling Dalvik: Memory Management in Android (Part 1 of 2)