P1678 烦恼的高考志愿题解
看了几个别人的题解,发现没有双指针的,想发一条。蒟蒻的第一篇题解,望通过。
题目大意
这题的题意挺明显的,就是给一个序列 a 和另一个序列 b ,找出序列 b 中每个元素在 a 中最相近的元素,并求出它们的差值的和。
二分思路
先
双指针思路
双指针和二分的比较
相比于二分的时间复杂度,双指针的时间复杂度约为 前提是你不会 stl。双指针的复杂度主要卡在一开始的排序,而在主要的计算片段,双指针的复杂度为
如何使用双指针
先用 sort 得到两个升序序列
这种方法跑的还是挺快的,虽然在本题没有达到最优解,但
实现代码
实现还是挺简单的,最好是自己先去打一下,下面的代码仅作参考。
#include<cstdio>
#include<cctype>
#include<algorithm>
#define INF 0x3F3F3F3F
#define For(i, j, k) for (register int i(j); i <= k; ++ i)
#define Rof(i, j, k) for (register int i(j); i >= k; -- i)
using namespace std;
inline int _min(int a, int b){return (a >= b) ? b : a;}
inline int read()
{
int x = 0, f = 1; char c = getchar();
while (!isdigit(c)){if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
x *= f; return x;
}
inline void write(long long x)
{
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
const int MAXN = 1000005;
int m, n;
int a[MAXN], b[MAXN];
int ans = INF;//循环中对于每个b[j]
long long tot;//累计答案
signed main()
{
m = read(); n = read();
For(i, 1, m) a[i] = read();
For(i, 1, n) b[i] = read();
a[0] = ~INF;//因为后面代码中要和a[0]进行相减取min,故设为最大
sort (a + 1, a + m + 1);
sort (b + 1, b + n + 1);
for (register int i(1), j(1); i <= m, j <= n;)
if (a[i] >= b[j])
tot += _min(ans, a[i] - b[j]), ++ j, ans = b[j] - a[i - 1];//累计答案,增加j指针,更新临时答案
else
{
ans = _min(ans, b[j] - a[i]);
if (i == m) tot += ans, ++ j, ans = b[j] - a[i];//若i已经指向最后一个了,后面的学生只能和a[i]进行求差
else ++ i;//a[i]不是最后一个,则求第一个大于等于b[j]的学校
}
write(tot);
return 0;
}