洛谷传送门
Atcoder传送门
题目大意
在一行中有 n n n个格子,从左往右编号为 1 1 1到 n n n。
有 2 2 2颗棋子,一开始分别位于位置 A A A和 B B B。按顺序给出 Q Q Q个要求,每个要求是如下形式:
- 给出一个位置 x i x_i xi,要求将两个棋子中任意一个移动到位置 x i x_i xi。
将一颗棋子移动一格需要花费 1 1 1秒,就是说将棋子从 X X X位置移动到 Y Y Y位置需要花费 ∣ X − Y ∣ |X-Y| ∣X−Y∣秒。
为了回答要求,你只能移动棋子,并且同一时刻只能移动一颗棋子。要求的顺序是不可更改的。在同一时间允许两颗棋子在同一个格子内。
输入输出格式
输入格式
第一行 4 4 4个整数,分别为 n , Q , A , B n,Q,A,B n,Q,A,B。
第二行 Q Q Q个整数,第 i i i个整数为 x i x_i xi。
- 1 ≤ n , Q ≤ 2 × 1 0 5 1\leq n,Q\leq 2\times 10^5 1≤n,Q≤2×105
- 1 ≤ A , B ≤ n 1\leq A,B\leq n 1≤A,B≤n
- 1 ≤ x i ≤ n 1\leq x_i\leq n 1≤xi≤n
输出格式
最小需要多少秒回答全部要求。
输入输出样例
输入样例#1:
8 3 1 8
3 5 1
输出样例#1:
7
输入样例#2:
9 2 1 9
5 1
输出样例#2:
4
输入样例#3:
9 2 1 9
5 9
输出样例#3:
4
输入样例#4:
11 16 8 1
1 1 5 1 11 4 5 2 5 3 3 3 5 5 6 7
输出样例#4:
21
输入样例#5:
8 3 1 8
3 5 1
输出样例#5:
7
输入样例#6:
9 2 1 9
5 1
输出样例#6:
4
输入样例#7:
9 2 1 9
5 9
输出样例#7:
4
输入样例#8:
11 16 8 1
1 1 5 1 11 4 5 2 5 3 3 3 5 5 6 7
输出样例#8:
21
解题分析
很妙妙暴力的一道题。 首先因为每次操作后一个棋子的位置是固定的, 我们有个很暴力的DP: 设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示第
i
i
i个操作后另外一枚棋子在
j
j
j时的最小代价, 那么就有:
d
p
[
i
]
[
x
i
−
1
]
=
m
i
n
{
d
p
[
i
−
1
]
[
j
]
+
∣
j
−
x
i
∣
}
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
∣
x
i
−
x
i
−
1
∣
(
j
≠
x
i
−
1
)
dp[i][x_{i-1}]=min\{dp[i-1][j]+|j-x_i|\} \\ dp[i][j]=dp[i-1][j]+|x_i-x_{i-1}|(j\ne x_{i-1})
dp[i][xi−1]=min{dp[i−1][j]+∣j−xi∣}dp[i][j]=dp[i−1][j]+∣xi−xi−1∣(j̸=xi−1)
下面那个就是个区间加操作, 上面那个把绝对值分类讨论了就是一个区间最小值的问题, 直接线段树维护。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <cctype>
#include <iostream>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define ls (now << 1)
#define rs ((now << 1) | 1)
#define MX 200500
#define gc getchar()
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
int n, q;
struct Node
{
ll val[3], tag;
Node(){std::memset(val, 63, sizeof(val));}
}tree[MX << 2];
IN void pushup(R int now)
{
tree[now].val[0] = min(tree[ls].val[0], tree[rs].val[0]);
tree[now].val[1] = min(tree[ls].val[1], tree[rs].val[1]);
tree[now].val[2] = min(tree[ls].val[2], tree[rs].val[2]);
}
IN void pushdown(R int now)
{
if (tree[now].tag)
{
tree[ls].val[0] += tree[now].tag;
tree[ls].val[1] += tree[now].tag;
tree[ls].val[2] += tree[now].tag;
tree[ls].tag += tree[now].tag;
tree[rs].val[0] += tree[now].tag;
tree[rs].val[1] += tree[now].tag;
tree[rs].val[2] += tree[now].tag;
tree[rs].tag += tree[now].tag;
tree[now].tag = 0;
}
}
void modify(R int now, R int lef, R int rig, R int pos, R ll v)
{
if (lef == rig)
{
tree[now].val[0] = v;
tree[now].val[1] = v - pos;
tree[now].val[2] = v + pos;
return;
}
pushdown(now);
int mid = lef + rig >> 1;
if (pos <= mid) modify(ls, lef, mid, pos, v);
else modify(rs, mid + 1, rig, pos, v);
pushup(now);
}
IN void add(R ll v)
{
tree[1].tag += v;
tree[1].val[0] += v;
tree[1].val[1] += v;
tree[1].val[2] += v;
}
ll query(R int now, R int lef, R int rig, R int lb, R int rb, R int id)
{
if (lef >= lb && rig <= rb) return tree[now].val[id];
pushdown(now);
int mid = lef + rig >> 1; ll ret = LONG_LONG_MAX;
if (lb <= mid) ret = query(ls, lef, mid, lb, rb, id);
if (rb > mid) ret = min(ret, query(rs, mid + 1, rig, lb, rb, id));
return ret;
}
int main(void)
{
int a, b, last, cur, del;
ll res1, res2, res3;
in(n), in(q), in(a), in(b);
in(last);
modify(1, 1, n, b, abs(last - a));
modify(1, 1, n, a, abs(last - b));
W (--q)
{
in(cur); del = abs(last - cur);
res1 = query(1, 1, n, cur, cur, 0) + del;
res2 = query(1, 1, n, 1, cur, 1) + cur;
res3 = query(1, 1, n, cur + 1, n, 2) - cur;
res1 = min(res1, min(res2, res3));
add(del);
modify(1, 1, n, last, res1);
last = cur;
}
printf("%lld", tree[1].val[0]);
}