zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    【PQ】学会逆透视、透视,专治表格多行并一行,一行拆多行【分分合合几时休,学会了马上休】
    【Pandas】concat拼接,plan shapes are not aligned列标号不一致问题
    【MySQL】Pivot功能 一行拆多行等
    【PowerQuery】制作年底倒计时提醒
    数据分析师8大能力
    【爬虫基础】如何查看网页编码
    Mysql 插入中文错误:Incorrect string value: 'xE7xA8x8BxE5xBAx8F...' for column 'course' at row 1
    【MySQL】日期函数、时间函数总结
    mysql相关问题总结
    2020年 10月17 日 我遇见了一个很好的,善解人意的女孩
  • 原文地址:https://www.cnblogs.com/OYJason/p/9825099.html
Copyright © 2011-2022 走看看