51Nod-1112-KGold
来源:互联网 发布:网络东北黑社会电影 编辑:程序博客网 时间:2024/06/11 11:57
ACM模版
描述
题解
做到这道题,一开始只考虑到了内存问题,而忽略了时间,所以用的优先队列存储,结果A了一半数据T了一半数据,代码One
。
然后看到一个初二小哥的代码,真的挺棒,总体思想是计算两条直线相交。
可以用二分搜索查找到第10000次超越发生在什么时刻。当然,这个判断函数很好写,就计算当前每一个人的金钱量,然后排序计算就行了。
首先以y轴为时间,x轴为金钱,之后就可以通过计算两条直线的交点来判断超越的时间,每次计算交点是O(1)的。
二分搜索O(n(logn)^2),然后计算是O(n^2)的(看起来不行,其实只有10000次会用到两直线相交的函数,其它根本不需要计算,严格来说是O(n^2/2),大部分循环体是非常简单的,因此足够,代码Two
)。
代码
One:
#include <iostream>#include <algorithm>#include <queue>#include <cstdio>using namespace std;const int MAXN = 1e4;const int MAXM = MAXN + 10;struct man{ int M; int S;} People[MAXM];class surpass{public: int A; int B; double time; surpass(int a, int b, double c) : A(a), B(b), time(c) {}};struct ans{ int A; int B;} Ans[MAXN];bool operator < (const surpass a, const surpass b){ if (a.time == b.time) { if (a.A == b.A) { return a.B < b.B; } return a.A < b.A; } return a.time < b.time;}priority_queue<surpass> q;int main(int argc, const char * argv[]){ int N; cin >> N; for (int i = 1; i <= N; i++) { scanf("%d %d", &People[i].M, &People[i].S); for (int j = 1; j <= i; j++) { if (People[i].S < People[j].S && People[i].M > People[j].M) { double time = (People[i].M - People[j].M) * 1.0 / (People[j].S - People[i].S); q.push(surpass(j, i, time)); } else if (People[i].S > People[j].S && People[i].M < People[j].M) { double time = (People[j].M - People[i].M) * 1.0 / (People[i].S - People[j].S); q.push(surpass(i, j, time)); } if (q.size() > MAXN) { q.pop(); } } } int key = 0; while (!q.empty()) { Ans[key].A = q.top().A; Ans[key++].B = q.top().B; q.pop(); } for (int i = key - 1; i >= 0; i--) { cout << Ans[i].A << ' ' << Ans[i].B << '\n'; } if (key == 0) { cout << "No Solution\n"; } return 0;}
Two:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define FOR(i, f, e) for (int i = (f); i < (e); i++)using namespace std;typedef long long ll;typedef pair<int, int> P;const int MAXN = 1e4;const int MAXM = MAXN + 5;// 判断直线相交pair<double, double> intersection(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3, ll x4, ll y4){ ll a0 = y1 - y2, b0 = x2 - x1, c0 = x1 * y2 - x2 * y1; ll a1 = y3 - y4, b1 = x4 - x3, c1 = x3 * y4 - x4 * y3; ll div = a0 * b1 - a1 * b0;// if (div == 0) // 不会相交// {// return make_pair(-1, -1);// } double x = (b0 * c1 - b1 * c0) / (double)div; double y = (a1 * c0 - a0 * c1) / (double)div; return make_pair(x, y);}int n;struct node{ int M, S, t; int id; // 按照M排序后序列号 int ordinal; // 原始序列号 inline bool operator < (const node &nd) { return t < nd.t; }} input[MAXM];struct RESULT{ int beyond, win; double time;} ans[MAXM * 2];bool cmp_1(const node &nd1, const node &nd2){ return nd1.M < nd2.M;}bool cmp_2(const RESULT &p1, const RESULT &p2){ if (p1.time == p2.time) { if (p1.win == p2.win) { return p1.beyond < p2.beyond; } return p1.win < p2.win; } return p1.time < p2.time;}int g_times(int time){ FOR(i, 0, n) { input[i].t = input[i].M + input[i].S * time; } sort(input, input + n); int res = 0; FOR(i, 0, n) { if (input[i].id < i) { res += i - input[i].id; } } return res;}int main(){ scanf("%d", &n); FOR(i, 0, n) { scanf("%d%d", &input[i].M, &input[i].S); input[i].ordinal = i; } sort(input, input + n, cmp_1); // 根据现有资产排序 FOR(i, 0, n) { input[i].id = i; } int l = 0, r = MAXM * 10, time = MAXM * 10; // 初始化一个比较大的r // 二分查找 查找出前MAXN次所需要的时间 while (l + 1 < r) { int mid = (l + r) / 2; int tmp = g_times(mid); time = mid; if (tmp == MAXN) { break; } else if (tmp < MAXN) { l = mid; } else { r = mid; } } int pos = 0; FOR(i, 0, n) // 现在的排序状态是按照time时间的状态从小到大排 { for (int j = i - 1; j >= 0; j--) { if (input[j].M > input[i].M) { pair<double, double> tmp = intersection(input[j].M, 0, input[j].t, time, input[i].M, 0, input[i].t, time); ans[pos].beyond = input[j].ordinal; ans[pos].win = input[i].ordinal; ans[pos++].time = tmp.second; } } } sort(ans, ans + pos, cmp_2); if (!pos) { printf("No Solution\n"); } else { int maxnum = min(pos, MAXN); FOR(i, 0, maxnum) { printf("%d %d\n", ans[i].win + 1, ans[i].beyond + 1); } } return 0;}
0 0
- 51Nod-1112-KGold
- 51Nod-1112-KGold(直线相交)
- 1112 KGold
- 51NOD1112 KGold
- 51Nod-1005-大数加法
- 51Nod-1011-最大公约数GCD
- 51Nod-1012-最小公倍数LCM
- 51Nod-1018-排序
- 51Nod-1019-逆序数
- 51Nod-1027-大数乘法
- 51Nod-1066-Bash游戏
- 51Nod-1069-Nim游戏
- 51Nod-1072-威佐夫游戏
- 51Nod-1073-约瑟夫环
- 51Nod-1085-背包问题
- 51Nod-1106-质数检测
- 51Nod-1135-原根
- 51Nod-1347-旋转字符串
- Chocolatey
- parNew+CMS,在minorGC发生前
- Eslint静态代码检查
- 括号配对问题
- Codeforces 459D 差异对数
- 51Nod-1112-KGold
- 读《About Face 4 交互设计精髓》11
- 面向对象的六大原则
- 聊一聊WEB前端安全那些事儿
- kill编程报错解决方法: Scatter Error: no default 'Read/Write' range selectedTarget
- Javascript总结--Array对象
- PageSet<T>分页
- linux基础命令大全
- 【adb】 pull和push的正确姿势