1. 程式人生 > >Arc073_F Many Moves

Arc073_F Many Moves

ret def log family namespace lse 除了 coder ==

傳送門

題目大意

有$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;
}

Arc073_F Many Moves