Arc073_F Many Moves
Posted oyjason
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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}|}$。
这个第二处转移中绝对值看起来非常碍眼,考虑将按照$jleq X_i,jgeq X_i$的情况变成了两类。
不难发现
对于$jleq X_i,F_{i+1,X_i}=min{F_{i,j}+X_{i+1}-j}$
对于$jgeq 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(mlog 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 ",maxn+ans); return 0; }
以上是关于Arc073_F Many Moves的主要内容,如果未能解决你的问题,请参考以下文章