zoukankan      html  css  js  c++  java
  • BZOJ3387 跨栏训练

    Description

    为了让奶牛参与运动,约翰建造了 $K$ 个栅栏。每条栅栏可以看做是二维平面上的一条线段,它们都平行于 X 轴。第 $i$ 条栅栏所覆盖的 X 轴坐标的区间为$[A_i,B_i]$,Y 轴高度就是 $i$。一开始,奶牛在坐标 $(S,K+1)$处,它们的家在原点处,所以要想要回家就必须“跨”一些栅栏。

    但奶牛们是跨不过栅栏的,它们只能绕过栅栏。在二维平面上,它们只能沿水平和垂直方向移动,如果前进的道路上出现栅栏,它们就不能前进,必须沿水平方向移动到没有栅栏的地方再前进。奶牛们希望走的路越短越好,由于在垂直方向上的路程是确定的,你只需要帮它们求出在水平方向的最短路程就可以了。

    Solution

    贪心地想,如果当前走到了一个线段的尽头,最优的选择是不继续行走,横坐标停留在线段端点,因为如果要走的话,可以等到下次遇到线段时再走

    并且从出发点走到原点的路程一定与从原点走到出发点的路程相同

    设$dp_{i,0/1}$为从原点走到第$i$条线段的左/右端点需要走的最小距离,$j_1,j_2$分别为$i$线段左右端点正下方第一条线段的编号,转移需要从该线段来

    $$dp_{i,0}=min(dp_{j,0}+|a_j-a_i|,dp_{j,1}+|b_j-a_i|)$$

    $$dp_{i,1}=min(dp_{j,0}+|a_j-b_i|,dp_{j,1}+|b_j-b_i|)$$

    将出发点视为一条$0$长线段

    数据:链接:https://pan.baidu.com/s/1qmrkh7Myb1ggXN1XIEl_MQ 提取码:p7ht

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int k,s,a[100005],b[100005];
    long long dp[100005][2];
    struct Seg
    {
        int val;
        bool tag;
    }tree[800050];
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            w=(w<<1)+(w<<3)+ch-'0';
            ch=getchar();
        }
        return f*w;
    }
    void pushdown(int i,int l,int r)
    {
        if(tree[i].tag)
        {
            tree[i<<1].val=tree[i<<1|1].val=tree[i].val;
            tree[i<<1].tag=tree[i<<1|1].tag=true;
            tree[i].tag=false;
        }
    }
    int query(int i,int l,int r,int p)
    {
        if(l==r)
        {
            return tree[i].val;
        }
        pushdown(i,l,r);
        int mid=l+r>>1;
        if(p<=mid)
        {
            return query(i<<1,l,mid,p);
        }
        return query(i<<1|1,mid+1,r,p);
    }
    void update(int i,int l,int r,int L,int R,int v)
    {
        if(L<=l&&r<=R)
        {
            tree[i]=(Seg){v,true};
            return;
        }
        pushdown(i,l,r);
        int mid=l+r>>1;
        if(L<=mid)
        {
            update(i<<1,l,mid,L,R,v);
        }
        if(R>mid)
        {
            update(i<<1|1,mid+1,r,L,R,v);
        }
    }
    int main()
    {
        k=read();
        s=read();
        for(int i=1;i<=k;i++)
        {
            a[i]=read();
            b[i]=read();
        }
        a[k+1]=b[k+1]=s;
        for(int i=1;i<=k+1;i++)
        {
            int temp1=query(1,1,200010,a[i]+100005),temp2=query(1,1,200010,b[i]+100005);
            dp[i][0]=min(dp[temp1][0]+abs(a[temp1]-a[i]),dp[temp1][1]+abs(b[temp1]-a[i]));
            dp[i][1]=min(dp[temp2][0]+abs(a[temp2]-b[i]),dp[temp2][1]+abs(b[temp2]-b[i]));
            if(a[i]+1<b[i])
            {
                update(1,1,200010,a[i]+100006,b[i]+100004,i);
            }
        }
        printf("%lld
    ",dp[k+1][0]);
        return 0;
    }
    跨栏训练
  • 相关阅读:
    使企点QQ来消息时不自动弹出窗口(以避免错过旧的消息和避免正在回复A时自动定位到B从而影响客服效率)
    8款开源聊天软件
    博客园设置皮肤(宽屏等)及选择文本编辑器
    Windows Server 2019 设置使用照片查看器查看图片
    使windows10重启后打开上次的文件夹和程序
    TinyMCE 5 富文本编辑器好
    wordpress 安装 Elementor PRO 插件(破解版)
    无法打印,提示“windows 打印后台处理程序 没有运行”的解决方案
    第一次将代码提交至git error: failed to push some refs to 'https://gitee.com/xxx/test.git'
    git本地和远程的关联问题
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13649661.html
Copyright © 2011-2022 走看看