题目传送门(内部题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. 七、单例设计模式共享数据分析、解决、call_once

    一.设计模式大概谈 代码的一些写法,与常规的写法不太一样,程序灵活,维护起来很方便,但是别人接管.阅读代码很痛苦. 用设计模式理念写出来的代码很晦涩.<< head first>&g ...

  2. LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理

    题目:https://loj.ac/problem/2721 1.注意别一输入 p[ i ] 就 a[ i ] %= p[ i ] ,因为在 multiset 里找的时候还需要真实值. 2.注意用 m ...

  3. 【前端技术】一篇文章搞掂:微信小程序

    实战: 1.[openId]获取openId 有如下几种方法: 通过wx.login()获取临时登录凭证 code,然后通过code2session获取openId wx.login():https: ...

  4. 第六周学习总结&实验报告四

    一.实验目的 (1)掌握类的继承 (2)变量的继承和覆盖,方法的继承,重载和覆盖的实现: 二.实验的内容 (1)根据下面的要求实现圆类Circle. 1.圆类Circle的成员变量:radius表示圆 ...

  5. 同时连接gitlab和github

    ---恢复内容开始--- 原文地址:https://juejin.im/post/5ac0cf356fb9a028df22c246 1. 分别生成gitlab和github的ssh key 生成第一个 ...

  6. 如何消去delphi Stringgrid重绘时产生重影

    procedure TForm1.Stringgrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGrid ...

  7. b/s 起点

    1.Web前端: JavaScript (1)脚本语言.JavaScript是一种解释型的脚本语言,C.C++等语言先编译后执行,而JavaScript是在程序的运行过程中逐行进行解释. (2)基于对 ...

  8. build temu error about SDL

    1. 安装sdl2 sudo apt-get install libsdl2-dev 2. 将configure文件中与SDL有关的地方改成SDL2 if test -z "$sdl&quo ...

  9. js的几个特殊的运算符略解

    js运算符的一些特殊应用及使用技巧. 1. 是否包含指定字符: ~ ~"str1".indexOf("str2") 含义为:str1 被查找的字符串 str2 ...

  10. 【Python-Django讲义】针对django的ppt讲义

    MCV思想: M是指数据模型,V是指用户界面,C则是控制器.使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式.比如一批统计数据你可以分别用柱状图.饼图来表示.C存在的目 ...