【luogu CF1693D】Decinc Dividing(DP)
Decinc Dividing
题目链接:luogu CF1693D
题目大意
给你一个排列,问你有多少个区间满足可以删掉一个单调递减子序列(可以是空的)得到一个单调递增数组。
思路
其实题目就是问你有多少个区间能划分成一个上升子序列和下降子序列。
首先我们考虑枚举左端点,往右扩展的时候 DP,那就是 n2n^2n2 的。
(因为有一个比较显然的性质是如果 [l,r][l,r][l,r] 不行 [l,r+1][l,r+1][l,r+1] 更加不行,所以固定左端点只有,合法的区间的右端点是一段前缀)
怎么 O(n)O(n)O(n) DP呢,一个事情就是你要用一维记录下两个序列的最后一个。
那必然有其中一个是你当前的位置,所以你只需要记录另一个位置即可。
那我们设:
fi,0f_{i,0}fi,0:iii 所在的递增,递减最后一个数最大值
fi,1f_{i,1}fi,1:iii 所在的递减,递增最后一个数最小值
(这个最大和最小是尽可能给后面留空间)
(其中 fi,0f_{i,0}fi,0 初始值为 −inf-inf−inf,fi,1f_{i,1}fi,1 初始值为 infinfinf,也代表无解值)
(然后初始化是 fi,0=inf,fi,1=−inff_{i,0}=inf,f_{i,1}=-inffi,0=inf,fi,1=−inf)
然后考虑转移,你就直接看新的数是放在哪个序列,能不能放。
考虑优化,我们试着左端点从右往左,每次新加入一个点会怎样呢?
好像不会咋样。
但是如果你 fi,0,fi,1f_{i,0},f_{i,1}fi,0,fi,1 DP 出来的结果跟之前一样,那你没必要继续下去,直接去上一轮的结果就行。
因为这个 DP 只会从 fi−1,0/1f_{i-1,0/1}fi−1,0/1 来更新 fi,0/1f_{i,0/1}fi,0/1。
那这个记忆化好像也没啥用。
我们试着看看每个位置的取值。
首先 inf,−infinf,-infinf,−inf 都有,那我们再看会不会有别的值。
以 fi,0f_{i,0}fi,0 为例子,fi,1f_{i,1}fi,1 同理。
我们找到 iii 前面最大的 jjj 使得 aj>aj+1a_j>a_{j+1}aj>aj+1,那 aj,aj+1a_j,a_{j+1}aj,aj+1 不能都在递增的序列中,那就要放到递减的,又因为是最大的 jjj,所以要么是 aja_jaj 做了最后的值,要么是 aj+1a_{j+1}aj+1。
那如果没有这个 jjj,那就是初始化 111 位置的 infinfinf。
如果无解,就是无解的 −inf-inf−inf。
那 fi,0f_{i,0}fi,0 就只有四种取值最多,fi,1f_{i,1}fi,1 也一样。
一个显然的事情是随着左端点的左移,这个值如果改变也只会单向的变化(变得更加容易无解)。
所以其实一个位置的值至多边 777 次,八种情况。
所以我们可以直接暴力从这个位置开始 DP,如果 DP 到的值跟之前的一样就直接用之前的位置作为答案进行贡献。
代码
#include<cstdio>
#include<iostream>
#define ll long long
#define INF (0x3f3f3f3f3f3f3f3f)using namespace std;const int N = 2e5 + 100;
int n, a[N], f[N][2], lst;
ll ans;
//0:i递增,递减最后一个数最大值
//1:i递减,递增最后一个数最小值 int slove(int i) {f[i][0] = INF; f[i][1] = -INF; int tmp = INF;for (int j = i + 1; j <= n; j++) {int v0 = -INF, v1 = INF;if (f[j - 1][0] != -tmp) {if (a[j] > a[j - 1]) v0 = max(v0, f[j - 1][0]);if (a[j] < f[j - 1][0]) v1 = min(v1, a[j - 1]);}if (f[j - 1][1] != tmp) {if (a[j] < a[j - 1]) v1 = min(v1, f[j - 1][1]);if (a[j] > f[j - 1][1]) v0 = max(v0, a[j - 1]);}if (v0 == f[j][0] && v1 == f[j][1]) break;f[j][0] = v0; f[j][1] = v1;if (f[j][0] == -tmp && f[j][1] == tmp) {lst = j - 1;return j - i;}}return lst - i + 1;
}int main() {scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%d", &a[i]);lst = n;for (int i = n; i >= 1; i--)ans += slove(i);printf("%lld", ans);return 0;
}
【luogu CF1693D】Decinc Dividing(DP)相关推荐
- 【CF 149D】Coloring Brackets(dp)
[CF 149D]Coloring Brackets(dp) D. Coloring Brackets time limit per test 2 seconds memory limit per t ...
- 【luogu P3214】卡农(数学)(DP)
卡农 题目链接:luogu P3214 题目大意 有 n 种元素,然后你要选 m 个互不相同的集合,满足里面有元素且在 n 种之间,每种至多一个,且每个元素在偶数个集合中出现过. 问你有多少种选法. ...
- 【洛谷】P1388 算式(dp)
题目描述 给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大.因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号.例如: N ...
- 【VIJOS - P1037】搭建双塔(dp)
题干: 描述 2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难.为了纪念"9?11"事件,Mr. F决定自己用水晶来搭建一座双塔. ...
- 【HDU - 2089 】不要62 (dp)
题干: 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客 ...
- 【BZOJ 1222】 [HNOI2001] 产品加工(DP)
Description 某加工厂有A.B两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成.由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时由两台机 ...
- 【luogu P4899】werewolf 狼人(最小生成树)(主席树)
werewolf 狼人 题目链接:luogu P4899 题目大意 给你一个无向图,然后每次要从一个地方走到另外一个地方. 然后你在走的过程中要在一个点转换形态,转换之前你只能走大于等于 L 的点,转 ...
- 【luogu CF1569D】Inconvenient Pairs(思维)
Inconvenient Pairs 题目链接:luogu CF1569D 题目大意 有一个方形网格,然后只有一些竖着的直线和横着的直线是可以走的(会给出它们的 x 坐标或 y 坐标). 然后会给你一 ...
- *【HDU - 5707】Combine String(dp)
题干: Given three strings aa, bb and cc, your mission is to check whether cc is the combine string of ...
最新文章
- jsp中include指令和动作的区别
- php----http协议 Cookie
- python图表之pygal入门篇
- DICOM医学图像处理:Dcmtk与fo-dicom保存文件的不同设计模式之“同步VS异步”+“单线程VS多线程”...
- golang中的recover
- TCL with SNPS - get_object_namesizeof_collectionstring
- 怎样把颜色转换为字符串
- UINavigationController扩展
- Altium Designer之原理图
- 使用SQL PLUS生成报表
- 企业综合能效管理系统,工业能耗解决方案
- 2018-2019-1 20165232 20165231 20165235实验二——固件程序设计
- Typora主要常用快捷键
- 常见计算机硬件故障维修方法,电脑硬件有哪些常见问题 电脑硬件常见问题维修技巧【详解】...
- 怎么把ppt文字大小设置一致_iPhone12暖屏怎么办 iPhone12暖屏解决方法
- 【生活】教你有效戒糖
- 【wpf】Page的Unloaded事件
- 零基础入门MySQL,让你对,MySQL有一定的了解
- Java Part1 Day11继承 方法重写 super多态
- 在中国,40岁程序员是如何工作的?