Arc073_F Many Moves

传送门

题目大意

有$n$个格子从左到右依次挨着,一开始有两枚棋子分布在$A,B$某一个或两个格子里,有$m$个操作,第$i$次操作要求你把其中一个棋子移到$X_i$上,移动一个棋子的代价是两个格子之间的距离,求移完所有棋子的代价之和的最小值。

 

题解

首先这题显然不能贪心,后面的要求会对当前的选择产生影响。

考虑朴素的$n^2$的$DP$,设$F_{i,k}$表示满足恰好前$i$个操作时,除了处在$X_i$处的棋子,另一个棋子处在$k$的格子处的代价。

那么转移很显然$F_{i+1,k}=F_{i,k}+|X_i-X_{i+1}|$。

特别的,有另一处转移$F_{i+1,X_i}=\min\{F_{i,j}+|j-X_{i+1}|\}$。

这个第二处转移中绝对值看起来非常碍眼,考虑将按照$j\leq X_i,j\geq X_i$的情况变成了两类。

不难发现

对于$j\leq X_i,F_{i+1,X_i}=\min\{F_{i,j}+X_{i+1}-j\}$

对于$j\geq X_i,F_{i+1,X_i}=\min\{F_{i,j}+j-X_{i+1}\}$

考虑用线段树维护$F_{i,j}-j,F_{i,j}+j$,每次第一处转移相当于全局加,第二种转移相当于取一个前缀或后缀的最小值,然后转移就是单点取$min$。

初始时,令$X_0=B,F_{0,A}=0$其余的$F=INF$,每次转移,每个点取$min$即可。

复杂度$O(m\log n)$。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
#define INF 10000000000000ll
using namespace std;
namespace IO{
	const int BS=(1<<20); char Buffer[BS],*HD,*TL;
	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
	int read(){
		int nm=0,fh=1; char cw=Getchar();
		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
		return nm*fh;
	}
}
using namespace IO;
int n,m,A,B,G[M]; LL maxn,p[M<<2][2],ans=INF;
void pushup(int x){
	p[x][0]=min(p[x<<1][0],p[x<<1|1][0]);
	p[x][1]=min(p[x<<1][1],p[x<<1|1][1]);
}
void build(int x,int l,int r){
	if(l==r){
		if(l==A) p[x][0]=-l,p[x][1]=l;
		else p[x][0]=p[x][1]=INF; return;
	}
	int mid=((l+r)>>1); build(x<<1,l,mid);
	build(x<<1|1,mid+1,r),pushup(x);
}
LL qry(int x,int l,int r,int L,int R,int kd){
	if(r<L||R<l) return INF; if(L<=l&&r<=R) return p[x][kd];
	int mid=((l+r)>>1); return min(qry(x<<1,l,mid,L,R,kd),qry(x<<1|1,mid+1,r,L,R,kd));
}
void mdf(int x,int l,int r,int pos,LL dt){
	if(l==r){p[x][0]=min(p[x][0],dt-l),p[x][1]=min(p[x][1],dt+l);return;}
	int mid=((l+r)>>1);if(pos<=mid) mdf(x<<1,l,mid,pos,dt);else mdf(x<<1|1,mid+1,r,pos,dt); pushup(x);
}
void dfs(int x,int l,int r){
	if(l==r){ans=min(ans,p[x][0]+(LL)l);return;}
	int mid=((l+r)>>1);dfs(x<<1,l,mid),dfs(x<<1|1,mid+1,r);
}
int main(){
	n=read(),m=read(),A=read(),B=read(),G[0]=B,build(1,1,n);
	for(int i=1;i<=m;i++){
		G[i]=read(); LL t1=G[i]+qry(1,1,n,1,G[i],0)+maxn;
		LL t2=qry(1,1,n,G[i],n,1)-G[i]+maxn,dt=abs(G[i]-G[i-1]);
		maxn+=dt,mdf(1,1,n,G[i-1],min(t1,t2)-maxn);
	} dfs(1,1,n),printf("%lld\n",maxn+ans); return 0;
}

 

posted @ 2018-10-21 15:07  OYJason  阅读(227)  评论(0编辑  收藏  举报