描述
题解
做到这道题,一开始只考虑到了内存问题,而忽略了时间,所以用的优先队列存储,结果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;
}