题目大意:有$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. __name__ 和 "__main__"

    本模块名: person 调用者模块名: start import sys def funcperson(): print('我是人') print(sys.modules[__name__]) # ...

  2. Trie(字典树,前缀树)_模板

    Trie Trie,又经常叫前缀树,字典树等等. Trie,又称前缀树或字典树,用于保存关联数组,其中的键通常是字符串.与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定.一个节点的 ...

  3. lnmp+phpmyadmin+laravel 环境配置

    腾讯云 Ubuntu16.04 添加用户 useradd 与 adduser Ubuntu下useradd不会在/home下自动创建与用户名同名的用户目录,而且不会自动选择shell版本,也没有设置密 ...

  4. 谭浩强第四版第九章课后习题12>>>建立一个链表,每个节点包括:学号、姓名、性别、年龄。输入一个年龄,若链表 中的结点所包含的年龄等于此年龄,则删除此结点。

    #include<stdio.h> #include<stdlib.h> #define N sizeof(link) typedef struct lin { struct ...

  5. struts2学习笔记一

    一.框架概述 1.框架的意义与作用: 所谓框架,就是把一些繁琐的重复性代码封装起来,使程序员在编码中把更多的经历放到业务需求的分析和理解上面. 特点:封装了很多细节,程序员在使用的时候会非常简单. 2 ...

  6. windows下subversion服务器搭建

    一.下载subversion服务器端和客户端软件 1.subversion下载地址:http://subversion.tigris.org/ 2.svn比较流行的客户端Tortoisesvn下载地址 ...

  7. jmeter使用beanshell构造参数化

    1.先在本地写一个java类,用来随机生成一个数字,如: package com.jmeter.test; public class BeanShellTest { public int getRan ...

  8. C++重载赋值操作符

    1.C++中重载赋值操作函数应该返回什么? 类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如 int x,y,z; x=y=z=15; 赋值行为相当 ...

  9. Linux-Shell脚本编程-学习-8-函数

    在这章往后的学习中,我讲尽可能详细的讲书中讲到的都记录到这里,以便以后方便查看. 什么是函数,函数就是一段代码,这段代码可以在我们需要的位置调用,那么这段代码就叫做函数. 在Shell中,定义一个函数 ...

  10. 虚拟现实-VR-UE4-编译UE4源码

    通过Git将UE4源代码获取到本地计算机 切记路径不要有中文 这里面我已经在进行编译了,有部分文件是多余出来的, 第一步就是点击 setup.bat批处理,这个过程回取决与你的网速的快慢,我等了一下午 ...