zoukankan      html  css  js  c++  java
  • 【arc073f】Many Moves(动态规划,线段树)

    【arc073f】Many Moves(动态规划,线段树)

    题面

    atcoder
    洛谷

    题解

    (f[i][j])表示第一个棋子在(i),第二个棋子在(j)的最小移动代价。
    发现在一次移动结束之后,总是有一个棋子会动到当前位置,因此状态改为当前是第(i)次操作,第(i)次操作没有动的那个棋子在(j)位置时的最小代价。
    把第一维省掉,用线段树动态维护这个数组。
    每次枚举移动哪一个棋子,直接线段树对应修改即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MAX 200200
    #define lson (now<<1)
    #define rson (now<<1|1)
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,Q,A,B,a[MAX];ll f[MAX];
    struct SegMentTree
    {
    	ll t[MAX<<2],tag[MAX<<2],a[MAX];
    	void pushup(int now){t[now]=min(t[lson],t[rson]);}
    	void Build(int now,int l,int r)
    	{
    		if(l==r){t[now]=f[l]+a[l];return;}
    		int mid=(l+r)>>1;tag[now]=0;
    		Build(lson,l,mid);Build(rson,mid+1,r);
    		pushup(now);
    	}
    	void puttag(int now,ll w){t[now]+=w;tag[now]+=w;}
    	void pushdown(int now)
    	{
    		if(!tag[now])return;
    		puttag(lson,tag[now]);
    		puttag(rson,tag[now]);
    		tag[now]=0;
    	}
    	void Modify(int now,int l,int r,int p,ll w)
    	{
    		if(l==r){t[now]=min(t[now],w);return;}
    		int mid=(l+r)>>1;pushdown(now);
    		if(p<=mid)Modify(lson,l,mid,p,w);
    		else Modify(rson,mid+1,r,p,w);
    		pushup(now);
    	}
    	void Modify(int now,int l,int r,int L,int R,int w)
    	{
    		if(L<=l&&r<=R){puttag(now,w);return;}
    		int mid=(l+r)>>1;pushdown(now);
    		if(L<=mid)Modify(lson,l,mid,L,R,w);
    		if(R>mid)Modify(rson,mid+1,r,L,R,w);
    		pushup(now);
    	}
    	ll Query(int now,int l,int r,int L,int R)
    	{
    		if(L<=l&&r<=R)return t[now];
    		int mid=(l+r)>>1;ll ret=4e18;pushdown(now);
    		if(L<=mid)ret=min(ret,Query(lson,l,mid,L,R));
    		if(R>mid)ret=min(ret,Query(rson,mid+1,r,L,R));
    		return ret;
    	}
    }T1,T2;
    ll Solve(int A,int B)
    {
    	memset(f,63,sizeof(f));f[B]=abs(A-a[1]);
    	for(int i=1;i<=n;++i)T1.a[i]=-i,T2.a[i]=i;
    	T1.Build(1,1,n);T2.Build(1,1,n);
    	ll inf=f[0];f[B]=inf;f[1]=abs(A-a[1]);
    	for(int i=2;i<=Q;++i)
    	{
    		ll ret=inf;
    		ret=min(ret,T1.Query(1,1,n,1,a[i])+a[i]);
    		ret=min(ret,T2.Query(1,1,n,a[i],n)-a[i]);
    		T1.Modify(1,1,n,1,n,abs(a[i]-a[i-1]));
    		T2.Modify(1,1,n,1,n,abs(a[i]-a[i-1]));
    		T1.Modify(1,1,n,a[i-1],ret-a[i-1]);
    		T2.Modify(1,1,n,a[i-1],ret+a[i-1]);
    		ret=min(ret,f[i-1]+abs(a[i]-a[i-1]));
    		f[i]=ret;
    	}
    	return f[Q];
    }
    int main()
    {
    	n=read();Q=read();A=read();B=read();
    	for(int i=1;i<=Q;++i)a[i]=read();
    	printf("%lld
    ",min(Solve(A,B),Solve(B,A)));
    	return 0;
    }
    
  • 相关阅读:
    丰清杨 作业 160809315
    自学C++游戏程序开发学习顺序(转)
    哈佛幸福课相关&积极心理学经典英文原版书籍读书笔记(连载中)(转)
    程序员追求的是什么?
    如何学好游戏编程?
    计算机专业的学生必须掌握的五门课程
    [译]学好数学能让程序员的水平更高
    天下没有免费的午餐
    各个类型书籍推荐
    Peter Norvig:自学编程,十年磨一剑
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10472691.html
Copyright © 2011-2022 走看看