题目大意:有$n$个位置$1,2,\dots n$;你有两个棋子$A$和$B$,你要进行$q$次操作,第$i$次操作给定一个$x_i$,你要选择一个棋子移动到$x_i$;求两个棋子最小移动的步数之和。

题解:一个$O(n^2)$的$DP$容易想到$f_{i,j}$表示到了第$i$步,另一个棋子在$j$这个位置。

$$f_{i,x_{i-1}}=\min\{f_{i-1,j}+|x_i-j|\}$$

$$f_{i,j}=f_{i-1,j}+|x_i-x_{i-1}|$$

下面一个还好做,可上面一个呢?

可以考虑拆成$j\leq x_i$和$j>x_i$来做

$$\therefore f_{i,x_{i-1}} =
\begin{cases}
f_{i-1,j}+x_i-j\quad(j\leq x_i)\\
f_{i-1,j}+j-x_i\quad(j>x_i)
\end{cases}$$

然后发现是区间修改求最小值,可以用线段树来做。

卡点:1.转移时把$x_{i-1}$写成了$x_{i}$

C++ Code:

#include <cstdio>
#include <cstring>
#define maxn 200010
using namespace std;
const long long inf = 0x3f3f3f3f3f3f3f3f;
inline long long min(long long a, long long b) {return a < b ? a : b;}
inline long long abs(long long a) {return a > 0 ? a : -a;}
int n, k, x, y;
int q, last;
long long V[maxn << 2][3], cov[maxn << 2];
void pushdown(int rt) {
int lc = rt << 1, rc = rt << 1 | 1;
long long &tmp = cov[rt];
V[lc][0] += tmp;
V[lc][1] += tmp;
V[lc][2] += tmp;
cov[lc] += tmp;
V[rc][0] += tmp;
V[rc][1] += tmp;
V[rc][2] += tmp;
cov[rc] += tmp;
tmp = 0;
}
void update(int rt) {
int lc = rt << 1, rc = rt << 1 | 1;
V[rt][0] = min(V[lc][0], V[rc][0]);
V[rt][1] = min(V[lc][1], V[rc][1]);
V[rt][2] = min(V[lc][2], V[rc][2]);
}
void add(int rt, int l, int r, int p, long long num) {
if (l == r) {
V[rt][0] = num;
V[rt][1] = num + l;
V[rt][2] = num - l;
return ;
}
if (cov[rt]) pushdown(rt);
int mid = l + r >> 1;
if (p <= mid) add(rt << 1, l, mid, p, num);
else add(rt << 1 | 1, mid + 1, r, p, num);
update(rt);
}
void add(long long num, int rt = 1) {
V[rt][0] += num;
V[rt][1] += num;
V[rt][2] += num;
cov[rt] += num;
}
long long ask(int rt, int l, int r, int L, int R, int op) {
if (L <= l && R >= r) return V[rt][op];
pushdown(rt);
int mid = l + r >> 1;
long long ans = inf;
if (L <= mid) ans = ask(rt << 1, l, mid, L, R, op);
if (R > mid) ans = min(ans, ask(rt << 1 | 1, mid + 1, r, L, R, op));
return ans;
}
int main() {
scanf("%d%d%d%d", &n, &k, &x, &y);
scanf("%d", &q);
memset(V, 0x3f, sizeof V);
add(1, 1, n, x, abs(y - q));
add(1, 1, n, y, abs(x - q));
while (--k) {
last = q; scanf("%d", &q);
long long t0 = ask(1, 1, n, last, last, 0) + abs(q - last);
long long t1 = ask(1, 1, n, q, n, 1) - q;
long long t2 = ask(1, 1, n, 1, q, 2) + q;
long long ans = min(t0, min(t1, t2));
add(abs(q - last));
add(1, 1, n, last, ans);
}
printf("%lld\n", V[1][0]);
return 0;
}

  

[AT2558]Many Moves的更多相关文章

  1. AT2558 [ARC073D] Many Moves

    开始被标签带骗了. 考虑一个\(dp\),\(f[i][j]\)代表有一个棋子在\(x_i\),另外一个\(j\)的最小答案. 那么考虑转移. 如果\(j != x_{i - 1}\) 那么答案自然贡 ...

  2. [LeetCode] Minimum Moves to Equal Array Elements II 最少移动次数使数组元素相等之二

    Given a non-empty integer array, find the minimum number of moves required to make all array element ...

  3. [LeetCode] Minimum Moves to Equal Array Elements 最少移动次数使数组元素相等

    Given a non-empty integer array of size n, find the minimum number of moves required to make all arr ...

  4. LeetCode Minimum Moves to Equal Array Elements II

    原题链接在这里:https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/ 题目: Given a non-empt ...

  5. LeetCode Minimum Moves to Equal Array Elements

    原题链接在这里:https://leetcode.com/problems/minimum-moves-to-equal-array-elements/ 题目: Given a non-empty i ...

  6. LeetCode 453 Minimum Moves to Equal Array Elements

    Problem: Given a non-empty integer array of size n, find the minimum number of moves required to mak ...

  7. Knight Moves

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  8. HDU 1372 Knight Moves

    最近在学习广搜  这道题同样是一道简单广搜题=0= 题意:(百度复制粘贴0.0) 题意:给出骑士的骑士位置和目标位置,计算骑士要走多少步 思路:首先要做这道题必须要理解国际象棋中骑士的走法,国际象棋中 ...

  9. [宽度优先搜索] HDU 1372 Knight Moves

    Knight Moves Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

随机推荐

  1. canvas实现半圆环形进度条

    html部分 <canvas id="canvas" width="150" height="150"> <p>抱歉 ...

  2. C# Regex正则验证规则

    using System; using System.Text.RegularExpressions; namespace MetarCommonSupport { /// <summary&g ...

  3. python爬取豆瓣流浪地球影评,生成词云

    代码很简单,一看就懂. (没有模拟点击,所以都是未展开的) 地址: https://movie.douban.com/subject/26266893/reviews?rating=&star ...

  4. HM16.0帧内预测重要函数笔记

    Void TEncSearch::estIntraPredQT   亮度块的帧内预测入口函数 Void TComPrediction::initAdiPatternChType 获取参考样本点并滤波 ...

  5. ABAP CDS ON HANA-(1)CDSビュー作成

    Basic CDS View Creation Open HANA Studio. Goto ABAP perspective. Open the project, Navigate to the p ...

  6. Django学习之天气调查实例(2):显示数据表数据

    数据表数据添加后,如添加3条用户信息,分别为“aaa”.“bbb”.“ccc”,现在通过代码的方式显示数据表中的数据. 1.在website项目文件夹中创建 userload.py文件,并且写如下代码 ...

  7. P2340 奶牛会展(状压dp)

    P2340 奶牛会展 题目背景 奶牛想证明它们是聪明而风趣的.为此,贝西筹备了一个奶牛博览会,她已经对N 头奶牛进行 了面试,确定了每头奶牛的智商和情商. 题目描述 贝西有权选择让哪些奶牛参加展览.由 ...

  8. 0301001_Lesson1&2

    Lesson 1 Excuse me! 对不起! Listen to the tape then answer this question.Whose handbag is it?听录音,然后回答问题 ...

  9. Koa基本使用

    简介 koa 是由 Express 原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的 Web 框架. 使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的 ...

  10. 在编程的时候,NotePad++ 中闪烁的光标突然有竖着闪烁的编程蓝色下划线闪烁的--小技巧告诉你-费元星

    当在写代码时出现的光标闪烁(横线闪烁) 在键盘上找 Insert ,按这个Insert就可以把横向闪烁光标( _ )修改成竖向闪烁光标样式( | ),横向光标会在你写代码的时候修改前面的代码,把光标移 ...