Portal -->arc073D

Description

​  有\(n\)个格子,编号从左到右为\(1\sim n\),一开始有两个棋子,位置给定,接下来要依次进行\(Q\)次操作,第\(i\)次操作必须选择一个棋子将其移动到\(x_i\)上面(\(x\)数组给定),所需代价是当前位置与目标位置的编号之差绝对值,允许两个棋子在同一个位置,求完成操作的最小代价

​  

Solution

​  大家好我是一个不会算复杂度的弱智选手

​  这题的话。。没有什么想法那就快乐dp咯。。但是状态的设置比较重要,注意到两个棋子其实本质上没有任何区别,我们希望用一种简明的方式将两个棋子的位置都记录下来,然后再注意到第\(i\)次操作完后一定有一个棋子在\(x_i\),那么我们可以用\(f[i][j]\)表示第\(i\)次操作完之后,不在\(x_i\)位置上的那个棋子在\(j\)这个位置,所用的最小代价

​​  那么可以写出转移:

\[f[i][j]=\begin{cases}
f[i-1][j]+|x_i-x_{i-1}|&(j\neq x_{i-1})\\
\\
min(f[i-1][j]+|x_i-x_{i-1}|,min(f[i-1][k]+|k-x_i|))&(j=x_{i-1})\\
\end{cases}
\]

​  其中\(k\)的枚举范围是\(1\sim n\)

​  现在最大的问题就是。。第二种情况,然而注意到比较开心的事情是这种情况只会在一个特定的位置出现所以我们可以考虑用某些数据结构得到这个\(min(f[i-1][k]+|k-x_i|)\)

​  那当然是用线段树啊,但是这个绝对值有点恶心,但是由于\(x_i\)已知,所以我们可以直接暴力处理一下,对于\(k\in[1,x_i]\)我们询问\(min(f[i-1][k]-k)\),对于\(k\in [x_i,n]\)我们询问\(min(f[i-1][k]+k)\),然后一个\(+x_i\)一个\(-x_i\)再取一下\(min\)就可以了(也就是说线段树分别维护\(f[i]\)、\(f[i]-i\)和\(f[i]+i\)的区间最小值)

​  至于\(f[i-1][j]+|x_i-x_{i-1}|\)的情况,我们直接区间打标记就好了

​  注意一下需要开long long

​  

​  mark:不要看到三个变量就觉得。。优化之后是\(n^2logn\)的。。。

​​  mark:遇到绝对值考虑暴力分两段,如果计算方式不同的话记得分界点两边的都要算

​  

​  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=200010,inf=2147483647;
int a[N];
namespace Seg{/*{{{*/
const int N=::N*4;
int ch[N][2];
ll mn[N][3],tag[N];//order: - none +
int n,tot;
void _build(int x,int l,int r){
for (int i=0;i<3;++i) mn[x][i]=inf;
if (l==r) return;
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
}
void build(int _n){n=_n; tot=1; _build(1,1,n);}
void pushup(int x){
for (int i=0;i<3;++i) mn[x][i]=min(mn[ch[x][0]][i],mn[ch[x][1]][i]);
}
void givetag(int x,ll delta){
tag[x]+=delta;
for (int i=0;i<3;++i) mn[x][i]+=delta;
}
void downtag(int x){
if (!tag[x]) return;
if (ch[x][0]) givetag(ch[x][0],tag[x]);
if (ch[x][1]) givetag(ch[x][1],tag[x]);
tag[x]=0;
}
void _update(int x,int d,int lx,int rx,ll delta){
if (lx==rx){
mn[x][0]=min(mn[x][0],delta-lx);
mn[x][1]=min(mn[x][1],delta);
mn[x][2]=min(mn[x][2],delta+lx);
return;
}
downtag(x);
int mid=lx+rx>>1;
if (d<=mid) _update(ch[x][0],d,lx,mid,delta);
else _update(ch[x][1],d,mid+1,rx,delta);
pushup(x);
}
void update(int d,ll delta){_update(1,d,1,n,delta);}
ll _query(int x,int l,int r,int lx,int rx,int op){
if (l<=lx&&rx<=r) return mn[x][op];
int mid=lx+rx>>1;
downtag(x);
if (r<=mid) return _query(ch[x][0],l,r,lx,mid,op);
else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx,op);
else{
return min(_query(ch[x][0],l,mid,lx,mid,op),_query(ch[x][1],mid+1,r,mid+1,rx,op));
}
pushup(x);
}
ll query(int l,int r,int op){return _query(1,l,r,1,n,op);}
}/*}}}*/
int n,m,st1,st2;
int Abs(int x){return x<0?-x:x;}
void debug(int op){
for (int i=1;i<=n;++i) printf("%lld ",Seg::query(i,i,op));
printf("\n");
}
void dp(){
ll tmp;
Seg::update(st2,0);
//debug(2);
for (int i=1;i<=m;++i){
tmp=min(Seg::query(1,a[i],0)+a[i],Seg::query(a[i],n,2)-a[i]);
Seg::givetag(1,Abs(a[i]-a[i-1]));
Seg::update(a[i-1],tmp);
//debug(1);
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%d%d%d",&n,&m,&st1,&st2);
for (int i=1;i<=m;++i) scanf("%d",a+i);
a[0]=st1;
Seg::build(n);
dp();
printf("%lld\n",Seg::query(1,n,1));
}

最新文章

  1. JavaScript方法call,apply,caller,callee,bind的使用详解及区别
  2. MongoVUE(MongoDB图像管理工具)
  3. springMVC分页,interceptor实现
  4. hdu 1005 1021 递归超限 找规律 // 只要看题中n较大都是有规律的
  5. CSS:权重和层叠规则决定了其优先级
  6. 使用VS2010调用matlab的mat格式文件
  7. 在Linux下安装C/C++开发工具包的最佳方式
  8. smarty实现缓存
  9. 常见排序算法(PHP实现)
  10. CentOS使用sendmail发送邮件
  11. windows phone因为墓碑化导致“正在恢复”的分析
  12. SQL语句分享[不定期更新]
  13. HDU 3691 Nubulsa Expo
  14. tt程序分析(一)
  15. Flask 构建微电影视频网站(七)
  16. select2使用小结
  17. ansible-play变量的基本应用
  18. 从无文件技术到使用隐写术:检查Powload的演变
  19. div等比例缩放-------纯CSS实现自适应浏览器宽度的正方形
  20. spark基础知识介绍(包含foreachPartition写入mysql)

热门文章

  1. ROS (Robot Operating System) 相关资料与文档
  2. python之multiprocessing创建进程
  3. Daily Scrum (2015/11/7)
  4. 第一个scrim任务分布
  5. Beta Scrum Day 3 — 听说
  6. 【图论】POJ-3255 次短路径
  7. BETA-5
  8. 四则运算web版
  9. 树莓派与Arduino Leonardo使用NRF24L01无线模块通信之基于RF24库 (六) 树莓派查询子节点温湿度数据
  10. WebDriver 工作原理