题目传送门(内部题49)


输入格式

第一行四个整数$n,q,a,b$。
接下来$n$行每行一个整数$p_i$。


输出格式

一行一个整数表示答案。


样例

样例输入:

10 3 3 7

样例输出:


数据范围与提示

对于$30\%$的数据:$n,q\leqslant 2,000$
对于所有数据:
$1\leqslant n,q\leqslant {10}^5$
$1\leqslant p_i\leqslant n$


题解

首先,我们考虑$30\%$的算法怎么办?

考虑$DP$,定义$dp[i][j]$表示到了第$i$步,一个指针在$p_i$,另一个指针在$j$的最短步数。

那么我们可以里出状态转移方程:

  $\alpha.dp[i][j]=dp[i-1][j]+|p_i-p_{i-1}|$(上一次和这一次移动的是一个指针)

  $\beta.dp[i][p_{i-1}]=dp[i-1][j]+|p_i-j|$(上一次和这一次移动的不是一个指针)

那么我们接着考虑如何优化。

发现转移$\alpha$其实就是将整个区间都加了$|p_i-p_{i-1}|$,而转移$\beta$我们可以维护$dp[i][j]+j$和$dp[i][j]-j$的最小值即可。

所以考虑线段树优化,即可得到满分。

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int n,q,a,b;
int p[100001];
long long tr[4][400001];
void pushup(int x)
{
tr[0][x]=min(tr[0][L(x)],tr[0][R(x)]);
tr[1][x]=min(tr[1][L(x)],tr[1][R(x)]);
tr[2][x]=min(tr[2][L(x)],tr[2][R(x)]);
}
void pushdown(int x)
{
if(!tr[3][x])return;
tr[0][L(x)]+=tr[3][x];
tr[0][R(x)]+=tr[3][x];
tr[1][L(x)]+=tr[3][x];
tr[1][R(x)]+=tr[3][x];
tr[2][L(x)]+=tr[3][x];
tr[2][R(x)]+=tr[3][x];
tr[3][L(x)]+=tr[3][x];
tr[3][R(x)]+=tr[3][x];
tr[3][x]=0;
}
void build(int x,int l,int r)
{
if(l==r)
{
if(l==b)
{
tr[0][x]=0;
tr[1][x]=l;
tr[2][x]=-l;
}
return;
}
int mid=(l+r)>>1;
build(L(x),l,mid);
build(R(x),mid+1,r);
pushup(x);
}
void change(int x,int l,int r,int w,long long k)
{
if(l==r)
{
tr[0][x]=min(tr[0][x],k);
tr[1][x]=tr[0][x]+l;
tr[2][x]=tr[0][x]-l;
return;
}
int mid=(l+r)>>1;
pushdown(x);
if(w<=mid)change(L(x),l,mid,w,k);
else change(R(x),mid+1,r,w,k);
pushup(x);
}
long long ask1(int x,int l,int r,int L,int R)
{
if(R<l||r<L)return 200209230020020923;
if(L<=l&&r<=R)return tr[2][x];
int mid=(l+r)>>1;
pushdown(x);
return min(ask1(L(x),l,mid,L,R),ask1(R(x),mid+1,r,L,R));
}
long long ask2(int x,int l,int r,int L,int R)
{
if(R<l||r<L)return 200209230020020923;
if(L<=l&&r<=R)return tr[1][x];
int mid=(l+r)>>1;
pushdown(x);
return min(ask2(L(x),l,mid,L,R),ask2(R(x),mid+1,r,L,R));
}
int main()
{
scanf("%d%d%d%d",&n,&q,&a,&b);
memset(tr[0],0x3f,sizeof(tr[0]));
memset(tr[1],0x3f,sizeof(tr[1]));
memset(tr[2],0x3f,sizeof(tr[2]));
build(1,1,n);
for(int i=1;i<=q;i++)
{
scanf("%d",&b);
tr[0][0]=min(ask1(1,1,n,1,b)+b,ask2(1,1,n,b,n)-b);
tr[0][1]+=abs(a-b);
tr[1][1]+=abs(a-b);
tr[2][1]+=abs(a-b);
tr[3][1]+=abs(a-b);
change(1,1,n,a,tr[0][0]);
a=b;
}
cout<<tr[0][1]<<endl;
return 0;
}

rp++

[CSP-S模拟测试]:F(DP+线段树)的更多相关文章

  1. [CSP-S模拟测试]:bird(线段树优化DP)

    题目传送门(内部题89) 输入格式 第一行两个数$n$和$k$,分别表示小鸟的只数和$R$装弹时间.接下来$n$行,每行两个数$l,r$表示$n$只小鸟初始时的头和尾的$x$坐标. 输出格式 输出一个 ...

  2. [CSP-S模拟测试]:Weed(线段树)

    题目描述 $duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹.为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验.电脑上面有若干层金坷垃,每次只能在上面撒上一层高度 ...

  3. [CSP-S模拟测试]:光线追踪(线段树)

    题目背景 初中时的乔猫试着组建了$NEWorld$开发组,可是不久之后却因为合作上的问题(和乔猫工程水平差,代码混乱的问题),开发组成员之间常常产生矛盾,关系越来越不如以前......一年下来,受到长 ...

  4. [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)

    题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...

  5. [CSP-S模拟测试]:string(线段树)

    题目描述 给定一个由小写字母组成的字符串$s$. 有$m$次操作,每次操作给定$3$个参数$l,r,x$. 如果$x=1$,将$s[l]~s[r]$升序排序: 如果$x=0$,将$s[l]~s[r]$ ...

  6. [CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

    题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j ...

  7. [CSP-S模拟测试]:f(Trie树+二分答案+meet in middle+two pointers)

    题目传送门(内部题67) 输入格式 第一行,三个整数$n$.$k$.$p$.第二行,$n$个自然数,表示$\{a_i\}$. 输出格式 输出一行,两个自然数,表示$f(res)$.$res$. 样例 ...

  8. ZOJ 3349 Special Subsequence 简单DP + 线段树

    同 HDU 2836 只不过改成了求最长子串. DP+线段树单点修改+区间查最值. #include <cstdio> #include <cstring> #include ...

  9. hdu 3016 dp+线段树

    Man Down Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  10. cf834D(dp+线段树区间最值,区间更新)

    题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...

随机推荐

  1. 远程桌面按键失效变成快捷键(远程桌面连接时会自动按下win键)

    三个电脑快捷键 (无意中学会三个快捷键了.....)win + L 锁屏win + D 切换到桌面win + F 搜索 在使用远程桌面连接Windows 2008操作系统,发现一个很烦的问题,经常发现 ...

  2. RHEL 使用epel源

    转自http://www.linuxidc.com/Linux/2012-10/71850.htm 设置epel源.方法如下: 32位系统选择:rpm -ivh http://download.Fed ...

  3. error MSB8008: 指定的平台工具集(v110)未安装或无效

    转自VC错误:http://www.vcerror.com/?p=318 问题描述: 平台工具集(v110)是vs2012下用的,你是用vs2010打开工程,它默认是用v100, 所以这个工程可能用v ...

  4. error C2065: ‘__in’ : undeclared identifier

    转自VC错误:http://www.vcerror.com/?p=1307 问题描述: 编译时出现: error C2065: '__in' : undeclared identifier error ...

  5. CentOS安装系统时硬盘分区建议

      一.常见挂载点的情况说明一般来说,在linux系统中都有最少两个挂载点,分别是/ (根目录)及 swap(交换分区),其中,/ 是必须的: 详细内容见下文: 安装系统时选择creat custom ...

  6. 用threading 解决 gunicorn worker timeout

    产生worker timeout 的背景 while 1: ..... time.sleep(1) gunicorn运行起来,只等待了30s,就卡住了,没报任何异常或err,查了gunicorn 官方 ...

  7. spring boot 尚桂谷学习笔记09 数据访问

    springboot 与数据库访问 jdbc, mybatis, spring data jpa,  1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...

  8. C语言博客作业04

    问题|答案 -|:-:|-: 这个作业属于哪个课程|c语言程序设计I 这个作业的要求在哪里|https://edu.cnblogs.com/campus/zswxy/CST2019-4/homewor ...

  9. 用vim写go代码——vim-go插件

    GoImport:导入包 GoImport!:导入远程包 GoImportAs: 导入包并且重命名

  10. Spring Boot开启的2种方式

    Spring Boot依赖 使用Spring Boot很简单,先添加基础依赖包,有以下两种方式 1. 继承spring-boot-starter-parent项目 <parent> < ...