*前置题目
136. 邻值查找

对于序列中的数 a i a_i ai找到前面和它差最小的一个数输出
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
const int N = 1e5 + 10, INF = 0x3f3f3f3f << 1;
int n;
struct Node {
int x, y;
bool operator< (const Node &n) const {
return x < n.x;
}
};
set<Node> s;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
int val;
cin >> val;
s.insert({
val, 1});
for (int i = 2; i <= n; ++i) {
cin >> val;
s.insert({
val, i});
auto it = s.find({
val, i});
Node ans = {
INF, 0};
if (++it != s.end()) {
ans = {
(*it).x - val, (*it).y};
}
it--;
if (it != s.begin()) {
it--;
if (val - (*it).x <= ans.x) {
ans = {
val - (*it).x, (*it).y};
}
}
cout << ans.x << " " << ans.y << "\n";
}
return 0;
}
题目
算法标签: 倍增优化, s e t set set
思路
不难发现, 小 A A A或者小 B B B从起始位置从一个位置出发, 走到的终点是确定的, 因此可以预处理小 A A A出发和小 B B B出发能走到的位置, 对于题目的第一个询问, 扫描一遍所有位置, 计算比值, 对于第二个询问直接模拟会超时, 因此需要优化
考虑倍增优化, 首先预处理出小 A A A和小 B B B从每个城市走最终能到达的城市 f [ 0 ] [ i ] [ j ] f[0][i][j] f[0][i][j]和 f [ 1 ] [ i ] [ j ] f[1][i][j] f[1][i][j], 0 0 0代表小 A A A, 1 1 1代表小 B B B, 从城市 i i i出发, 走 2 j 2 ^ j 2j步到达的城市
还要预处理走过的距离, 分为 d a da da数组和 d b db db数组, 有下面四个情况, d a [ 0 ] [ i ] [ j ] , d a [ 1 ] [ i ] [ j ] , d b [ 0 ] [ i ] [ j ] , d b [ 1 ] [ i ] [ j ] da[0][i][j], da[1][i][j], db[0][i][j], db[1][i][j] da[0][i][j],da[1][i][j],db[0][i][j],db[1][i][j], 前两项代表 A A A走过的距离, 后两项代表 B B B走过的距离, 这样就可以迅速的计算出询问 2 2 2
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<LL, int> PLI;
const int N = 100010, M = 17;
const LL INF = 1e18;
int n, h[N];
int ga[N], gb[N];
int f[2][N][M];
LL da[2][N][M];
LL db[2][N][M];
void init_g() {
set<PLI> s;
s.insert({
INF, 0}), s.insert({
INF + 1, 0});
s.insert({
-INF, 0}), s.insert({
-INF - 1, 0});
PLI cand[4];
for (int i = n; i >= 1; i--) {
PLI t(h[i], i);
auto j = s.upper_bound(t);
j++;
for (int k = 0; k < 4; k++) {
cand[k] = *j;
j--;
}
LL d1 = INF, d2 = INF;
int p1 = 0, p2 = 0;
for (int k = 3; k >= 0; k--) {
LL d = abs(h[i] - cand[k].x);
if (d < d1) {
d2 = d1, d1 = d;
p2 = p1, p1 = cand[k].y;
}
else if (d < d2) {
d2 = d;
p2 = cand[k].y;
}
}
ga[i] = p2, gb[i] = p1;
s.insert(t);
}
}
void init_f() {
// 初始化第0阶
for (int i = 1; i <= n; i++) {
f[0][i][0] = ga[i];
f[1][i][0] = gb[i];
}
for (int j = 1; j < M; j++) {
for (int i = 1; i <= n; i++) {
for (int k = 0; k < 2; k++) {
if (j == 1) {
f[k][i][j] = f[1 - k][f[k][i][0]][0];
}
else {
f[k][i][j] = f[k][f[k][i][j - 1]][j - 1];
}
}
}
}
}
// 计算两个城市之间的距离
int get_dist(int a, int b) {
return abs(h[a] - h[b]);
}
// 初始化距离数组da和db
void init_d() {
// 初始化第0阶距离
for (int i = 1; i <= n; i++) {
da[0][i][0] = get_dist(i, ga[i]);
db[1][i][0] = get_dist(i, gb[i]);
}
// 计算更高阶的距离
for (int j = 1; j < M; j++) {
for (int i = 1; i <= n; i++) {
for (int k = 0; k < 2; k++) {
if (j == 1) {
da[k][i][j] = da[k][i][j - 1] + da[1 - k][f[k][i][j - 1]][j - 1];
db[k][i][j] = db[k][i][j - 1] + db[1 - k][f[k][i][j - 1]][j - 1];
}
else {
da[k][i][j] = da[k][i][j - 1] + da[k][f[k][i][j - 1]][j - 1];
db[k][i][j] = db[k][i][j - 1] + db[k][f[k][i][j - 1]][j - 1];
}
}
}
}
}
// 计算从s出发,最多行驶x距离,A和B分别行驶的距离
void calc(int s, int x, int &la, int &lb) {
la = lb = 0;
for (int i = M - 1; i >= 0; i--) {
if (f[0][s][i] && la + lb + da[0][s][i] + db[0][s][i] <= x) {
la += da[0][s][i];
lb += db[0][s][i];
s = f[0][s][i];
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> h[i];
init_g();
init_f();
init_d();
int x;
cin >> x;
int res = 0, max_h = 0;
double min_ra = INF;
for (int i = 1; i <= n; i++) {
int la, lb;
calc(i, x, la, lb);
double ra = lb ? (double) la / lb : INF;
if (ra < min_ra || (ra == min_ra && h[i] > max_h)) {
min_ra = ra;
max_h = h[i];
res = i;
}
}
cout << res << "\n";
int q;
cin >> q;
while (q--) {
int s, x;
cin >> s >> x;
int la, lb;
calc(s, x, la, lb);
cout << la << " " << lb << "\n";
}
return 0;
}


京公网安备 11010502036488号