题目大意:
  有一排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. Django之动态验证码的生成

    kind.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  2. 蓝色的PC端后台管理界面设计模板——后台

    链接:http://pan.baidu.com/s/1o82hXX4 密码:x6le

  3. python基础===数据伪造模块faker

    介绍文档: https://pypi.org/project/Faker/ https://faker.readthedocs.io/en/latest/ https://faker.readthed ...

  4. HttpURLConnection传json

    private static String sendToWangTing(DataRow dataRow) throws IOException{ String ip = Configuration. ...

  5. Linux 上配置 NTP SERVER

    在CENTOS 6.2上面安装配置NTP SERVER 安装NTP:yum install ntp 配置时间源vi /etc/ntp.confserver 210.72.145.44server nt ...

  6. 【BubbleCup X】F:Product transformation

    按照题解的规律,首先能看出前面每个数幂次的性质. 然后发掘约数的性质 #include<bits/stdc++.h> ; typedef long long ll; using names ...

  7. 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树

    题目传送门 题意 具体的自己去上面看吧...反正不是权限题. 简单来说,就是定义了一类新的数,每个数是0或者为 \((x_L, x_R)\) ,同时定义比较大小的方式为:非零数大于零,否则按字典序比较 ...

  8. php 面试指南

    https://xianyunyh.gitbooks.io/php-interview/

  9. iBatis应用--控制执行SQL时的超时时间

    https://blog.csdn.net/jackie_xiaonan/article/details/8459320

  10. Hadoop(八)Hadoop数据压缩与企业级优化

    一 Hadoop数据压缩 1.1 概述 压缩技术能够有效减少底层存储系统(HDFS)读写字节数.压缩提高了网络带宽和磁盘空间的效率.在Hadood下,尤其是数据规模很大和工作负载密集的情况下,使用数据 ...