BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】

Description

给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。

选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。

求出L的最大值。

Input

第一行两个正整数,分别表示N和K (N, K <= 500,000)。

第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。

第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。

Output

一个正整数,表示L的最大值。

Sample Input

7 3

2 4 3 1 3 5 3

< > =

Sample Output

6

HINT

选出的子序列为2 4 3 3 5 3,相邻大小关系分别是< > = < >。


思路

暴力的思想是考虑DP

\(dp_{i,j}\)表示以i这一位结束长度为j是否可行

但是发现状态非常冗杂,考虑怎么对状态进行压缩

发现当前的dp状态对后面的影响只有当前数的大小和当前串的长度

又因为我们需要最大化当前串的长度所以可以考虑把当前串的长度进行转化

发现转移的时候需要快速进行一个在值域上进行前缀/后缀/单点查寻的操作

所以可以用线段树维护结尾每个数的大小所能达到的最大dp值,因为还有符号限制,所以就可以用三个线段树维护

然后尝试证明当前dp值在一种符号达到最大的时候一定最优

因为我们的DP只需要考虑当前状态的最佳决策,所以我们不考虑当前状态之后会发生什么

那么接下来就需要证明

  • 当i从一个决策点j进行转移的时候,当且仅当j取到最优值
  • 也就是说如果j这个点在答案序列中出现,位置只可能是\(dp_j\)

那么我们假设i是第一个i,有j<i满足\(dp_{j}=x\)

而j出现在答案中一个不是x的位置y(y<x),而此时\(dp_{i}\)能更大

首先a[j]与a[i]一定不满足位置x的大小关系,且能满足位置y的大小关系,所以x和y符号一定不相同

而\(a_{i}=a_{j}\)时一定能取到最大值,因为所有j可以转移的位置i都可以转移,i可以顶替j的位置

所以这个时候\(a_i!=a_j\)

由此可以推出位置y的符号不是等于号

因为\(dp_j=x\),且i是第一个i满足由非j的地方转移过来,所以一定存在k<j,\(dp_k=y\)

那么我们一定有\(a_k\)与\(a_i\)不满足位置y的符号,否则i可以由k转移而j在位置y就没有意义了

假设x位置是小于号,那么y位置一定是大于号,且一定有\(a_k<a_i\)

因为\(dp_j=x\),那么一定存在l满足k<l<j,\(a_l<a_k<a_i\)且\(dp_l\)的位置是小于号,所以\(dp_i\)一定可以由\(dp_l\)转移并且比从位置y转移更优

x上的符号是其他的时候证明类似


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e6 + 10;
#define LD (t << 1)
#define RD (t << 1 | 1)
struct Segment_Tree {
int maxv[N << 2];
void modify(int t, int l, int r, int pos, int vl) {
maxv[t] = max(maxv[t], vl);
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) modify(LD, l, mid, pos, vl);
else modify(RD, mid + 1, r, pos, vl);
}
int query(int t, int l, int r, int ql, int qr) {
if (ql > qr) return 0;
if (ql <= l && r <= qr) return maxv[t];
int mid = (l + r) >> 1;
if (qr <= mid) return query(LD, l, mid, ql, qr);
else if (ql > mid) return query(RD, mid + 1, r, ql, qr);
return max(query(LD, l, mid, ql, mid), query(RD, mid + 1, r, mid + 1, qr));
}
} segment_tree1, segment_tree2, segment_tree3;
int n, k, a[N], dp[N], s[N];
int len = 0, ans = 0;
char c[3];
int main() {
Read(n); Read(k);
fu(i, 1, n) {
Read(a[i]);
len = max(len, a[i]);
}
fu(i, 1, k) {
scanf("%s", c);
if (c[0] == '=') s[i] = 1;
if (c[0] == '>') s[i] = 2;
if (c[0] == '<') s[i] = 3;
}
fu(i, 1, n) {
dp[i] = max(dp[i], segment_tree1.query(1, 1, len, a[i], a[i]) + 1);
dp[i] = max(dp[i], segment_tree2.query(1, 1, len, a[i] + 1, len) + 1);
dp[i] = max(dp[i], segment_tree3.query(1, 1, len, 1, a[i] - 1) + 1);
int ind = (dp[i] - 1) % k + 1;
if (s[ind] == 1) segment_tree1.modify(1, 1, len, a[i], dp[i]);
if (s[ind] == 2) segment_tree2.modify(1, 1, len, a[i], dp[i]);
if (s[ind] == 3) segment_tree3.modify(1, 1, len, a[i], dp[i]);
ans = max(ans, dp[i]);
}
Write(ans);
return 0;
}

BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】的更多相关文章

  1. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  2. [AGC011F] Train Service Planning [线段树优化dp+思维]

    思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...

  3. 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

    题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...

  4. POJ 2376 Cleaning Shifts (线段树优化DP)

    题目大意:给你很多条线段,开头结尾是$[l,r]$,让你覆盖整个区间$[1,T]$,求最少的线段数 题目传送门 线段树优化$DP$裸题.. 先去掉所有能被其他线段包含的线段,这种线段一定不在最优解里 ...

  5. 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$

    正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...

  6. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  7. 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点

    容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...

  8. Codeforces 1603D - Artistic Partition(莫反+线段树优化 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 学 whk 时比较无聊开了道题做做发现是道神题( 介绍一种不太一样的做法,不观察出决策单调性也可以做. 首先一个很 trivial 的 o ...

  9. 2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)

    2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP) https://www.luogu.com.cn/problem/P1848 题意: 当农夫约翰闲 ...

随机推荐

  1. Browserify命令行参数

    –outfile, -o: browserify日志打印到文件 –require, -r: 绑定模块名或文件,用逗号分隔 –entry, -e: 应用程序的入口 –ignore, -i: 省略输出 – ...

  2. 8条规则图解JavaScript原型链继承原理

    原形链是JS难点之一,而且很多书都喜欢用一大堆的文字解释给你听什么什么是原型链,就算有图配上讲解,有的图也是点到为止,很难让人不产生疑惑. 我们先来看一段程序,友情提示sublimeText看更爽: ...

  3. python之Memcached 安装及操作

    一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...

  4. thinkphp3.2.3定时任务 不能获取本模块config, 不能获取本模块的其他配置

    一开始创建就有一个home模块再创建一个Data模块 定时任务在/Application/Common/Conf/crons.php中,这里不讲怎么创建定时任务. Data模块的配置文件路径如下/Ap ...

  5. 一、nginx 安装

    添加官方 yum 源 vim /etc/yum.repos.d/nginx.rep 输入以下内容(OS为你的系统,OSRELEASE 系统版本) [nginx] name=nginx repo bas ...

  6. 新东方雅思词汇---9.1、sist

    新东方雅思词汇---9.1.sist 一.总结 一句话总结: 站 resist 英 [rɪ'zɪst]  美 [rɪ'zɪst]  vi. 抵抗,抗拒:忍耐 vt. 抵抗:忍耐,忍住 n. [助剂] ...

  7. Centos7 使用Dockerfile 制作自己的Dotnetcore程序镜像

    准备Centos7环境及Docker环境 从Docker hub拉取 Microsoft/dotnet 基础镜像(可以使用国内加速) 向Centos7指定目录上传Dotnet Core程序,目录: / ...

  8. 奔跑吧ansible笔记一(概述)

    1.普通用户想使用sudo到root用户下执行一些有root权限的操作需要在被管理机器上做如下操作 1.切换到root用户下,怎么切换就不用说了吧,不会的自己百度去. 2.添加sudo文件的写权限,命 ...

  9. CF 913 A

    题解: 首先判断n是否大于30 大于30输出m 否则输出m%2^n 代码: #include<bits/stdc++.h> using namespace std; int n,m; in ...

  10. js的 style.width 取不到元素的宽度值

    以前一直用jquery的.width()方法来获取一个元素的当前的宽度.不管该元素是否设置了宽度,CSS样式是内联.外联or内嵌,都可用此方式获得元素当前的宽度. 今天想用原生JS想获取一个元素宽度时 ...