题目大意:
  有一排n个格子和2枚硬币。
  现在有q次任务,每一次要你把其中一枚硬币移到x的位置上,移动1格的代价是1。
  两枚硬币不能同时移动,任务必须按次序完成。
  现在告诉你两枚硬币初始状态所在的位置a和b,问完成所有任务的最小代价。

思路:
  很容易想到一个O(qn)的DP。
  由于完成任务的次序确定,每个任务的位置也确定,我们可以用f[i][j]表示完成第i个任务后,一个硬币在x[i],一个硬币在j的最小代价。
  转移方程为f[i][j]=min{f[i-1][j]+|x[i]-x[i-1]|},f[i][a[i-1]]=min{f[i-1][j]+|x[i]-j|}。
  然而这样还是会TLE,在AtCoder上只过了14/34的测试数据。
  不难发现,在状态转移方程中,如果我们能去掉绝对值,里面的东西就能用线段树维护。
  而绝对值的取值只与硬币的左右位置关系有关。
  因此我们可以建2棵线段树,一棵表示被转移的状态在目标状态左边,一棵表示在右边。
  左线段树中每个叶子结点x[i-1]维护f[i-1][j]-x[i-1]的值,右线段树每个叶子结点x[i-1]维护f[i-1][j]+x[i-1]的值。
  看了一下榜,发现排在前面的基本上都是用树状数组做的。
  然而用树状数组维护区间最值难道不是O(log^2 n)的吗?
  事实上我们可以发现线段树上维护的东西只会越来越小,这样我们可以直接在树状数组上修改,不用考虑原来的最小值没了怎么办。
  然后我又在树状数组里面加了一个剪枝。
  这样随随便便就能拿Rank1。

 #include<cstdio>
#include<cctype>
#include<cstdlib>
#include<algorithm>
typedef signed long long int int64;
inline unsigned getint() {
register char ch;
while(!isdigit(ch=getchar()));
register unsigned x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline int64 min(const int64 &a,const int64 &b) {
return a<b?a:b;
}
const int64 inf=0x7ffffffffffffff;
const int N=;
int n;
class FenwickTree {
private:
int64 val[N];
int lowbit(const int &x) const {
return x&-x;
}
public:
FenwickTree() {
std::fill(&val[],&val[N],inf);
}
void modify(int p,const int64 &x) {
while(p<=n) {
if(x<val[p]) {
val[p]=x;
} else {
return;
}
p+=lowbit(p);
}
}
int64 query(int p) const {
int64 ret=inf;
while(p) {
ret=min(ret,val[p]);
p-=lowbit(p);
}
return ret;
}
};
FenwickTree ta;
class RevFenwickTree {
private:
int64 val[N];
int lowbit(const int &x) const {
return x&-x;
}
public:
RevFenwickTree() {
std::fill(&val[],&val[N],inf);
}
void modify(int p,const int64 &x) {
while(p) {
if(x<val[p]) {
val[p]=x;
} else {
return;
}
p-=lowbit(p);
}
}
int64 query(int p) const {
int64 ret=inf;
while(p<=n) {
ret=min(ret,val[p]);
p+=lowbit(p);
}
return ret;
}
};
RevFenwickTree tb;
int64 f[N];
inline void modify(const int &p,const int64 x) {
if(x<f[p]) {
f[p]=x;
ta.modify(p,x-p);
tb.modify(p,x+p);
}
}
int main() {
n=getint();
int q=getint(),a=getint(),b=getint();
std::fill(&f[],&f[N],inf);
modify(a,);
int64 sum=;
while(q--) {
a=b;
b=getint();
sum+=abs(a-b);
int64 t1=ta.query(b)+b,t2=tb.query(b)-b;
modify(a,min(t1,t2)-abs(a-b));
}
int64 tmp=inf;
for(register int i=;i<=n;i++) {
tmp=min(tmp,f[i]);
}
printf("%lld\n",tmp+sum);
return ;
}

原来的O(n^2)DP程序:

 #include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
inline unsigned getint() {
register char ch;
while(!isdigit(ch=getchar()));
register unsigned x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline unsigned min(const unsigned &a,const unsigned &b) {
return a<b?a:b;
}
const unsigned N=;
unsigned long long f[][N];
unsigned a[];
int main() {
unsigned n=getint(),q=getint();
memset(f[],0xff,n<<);
a[]=getint()-,f[][getint()-]=;
for(register unsigned i=;i<=q;i++) {
a[i&]=getint()-;
memset(f[i&],0xff,n<<);
for(register unsigned j=;j<n;j++) {
if(!~f[~i&][j]) continue;
f[i&][j]=min(f[i&][j],f[~i&][j]+abs(a[i&]-a[~i&]));
f[i&][a[~i&]]=min(f[i&][a[~i&]],f[~i&][j]+abs(a[i&]-j));
}
}
unsigned long long ans=~;
for(register unsigned i=;i<n;i++) {
ans=min(ans,f[q&][i]);
}
printf("%llu\n",ans);
return ;
}

[AtCoder-ARC073F]Many Moves的更多相关文章

  1. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  2. 【arc073f】Many Moves(动态规划,线段树)

    [arc073f]Many Moves(动态规划,线段树) 题面 atcoder 洛谷 题解 设\(f[i][j]\)表示第一个棋子在\(i\),第二个棋子在\(j\)的最小移动代价. 发现在一次移动 ...

  3. 【ARC073F】Many Moves

    题目 一个显然的\(dp\),设\(dp_{i,j}\)表示其中一个棋子在\(x_i\)点,另一个棋子在\(j\)点的最小花费 显然\(dp_{i,j}\)有两种转移 第一种是把\(x_i\)上的棋子 ...

  4. [atcoder contest 010] F - Tree Game

    [atcoder contest 010] F - Tree Game Time limit : 2sec / Memory limit : 256MB Score : 1600 points Pro ...

  5. AtCoder Beginner Contest 151 题解报告

    总的来说,这次的题目比较水,然而菜菜的我并没有把所有题目都做完,话不多说,直接来干货: A:Next Alphabet 题目链接:https://atcoder.jp/contests/abc151/ ...

  6. [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 ...

  7. [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 ...

  8. LeetCode Minimum Moves to Equal Array Elements II

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

  9. LeetCode Minimum Moves to Equal Array Elements

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

  10. 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 ...

随机推荐

  1. Vue笔记之props验证

    使用props 在Vue中父组件向子组件中传送数据是通过props实现的,一个简单的使用props的例子: <!DOCTYPE html> <html> <head> ...

  2. React Native 与 夜神模拟器的绑定

    之前一直用真机去调试, 每回更新一次都需要手动摇晃手机后才能reload JS, OMG,太麻烦了. 后来寻思模拟器网上推荐用Geny...什么的模拟器,但是那个模拟器还需要VBox一起用. 有点麻烦 ...

  3. 【IDEA】与Eclipse "Link with Editor"等价功能设置

    Link With Editor是Eclipse内置功能中十分小巧,但却异常实用的一个功能.这个开关按钮 (Toggle Button) 出现在各式导航器视图 ( 例如 Resource Explor ...

  4. HDU 6205 2017沈阳网络赛 思维题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6205 题意:给你n堆牌,原本每一堆的所有牌(a[i]张)默认向下,每次从第一堆开始,将固定个数的牌(b ...

  5. c/c++中static用法总结

    static的作用主要有两种: 第一个作用是限定作用域:第二个作用是保持变量内容持久化: c语言中static的用法: 1.全局静态变量: 用法:在全局变量前加上关键字static,全局变量就定义成一 ...

  6. angular项目文件概览

    在Mac上打开终端,输入ng new b-app  如下: 然后在webstorm中打开 src文件夹 你的应用代码位于src文件夹中. 所有的Angular组件.模板.样式.图片以及你的应用所需的任 ...

  7. Python学习笔记——数据结构和算法(二)

    1.字典中一个键映射多个值 可以使用collections中的defaultdict来实现,defalultdict接受list或者set为参数 from collections import def ...

  8. 进程一些命令pstree,ps,pstack,top

    1. pstree pstree以树结构显示进程$ pstree -p work | grep adsshd(22669)---bash(22670)---ad_preprocess(4551)-+- ...

  9. C语言 五子棋2

    #include<windows.h> #include<stdlib.h> #include<stdio.h> #include<conio.h> # ...

  10. python ConfigParser 配置读写

    我们写程序的时候一般都会写程序包的时候,很少硬编码写在一起,这有个很好的配置文件包. 参考 ConfigParser  和   ConfigParser 的使用 一.ConfigParser 简介 C ...