紫薯例题+1。

题意:给你一个长度为n(n<=200000)的序列a[n],求删除一个连续子序列后的可能的最长连续上升子序列的长度。

首先对序列进行分段,每一段连续的子序列的元素递增,设L[i]为下标i对应的元素向左能延伸到的最大长度(在同一段内),R[i]为向右能延伸到的最大长度,则问题转化成了对于每个下标i,找到在它前面的下标j中a[j]<a[i]且L[j]最大的j,然后用R[i]+L[j]去更新ans。

第一种方法是用一个二元组(x,y)表示大小为x的元素所对应的L的值,用一个set保存所有这样的二元组,则任意两个二元组不存在包含关系,即满足x递增且y也递增。于是对原序列从左往右扫一遍,每扫到一个元素,就可以从set中二分找到最大的x使得a[i]>x,用R[i]+y去更新ans即可。然后向set中插入(a[i],L[i]),并根据set中左右两边的二元组的值来确定是否需要保留它,并清掉一些无用的二元组。

这里用到了一点小技巧,就是向set中插入两个虚的元素作为左右边界,这样就不用特判了,方便了很多。

 #include<bits/stdc++.h>

 using namespace std;
typedef long long ll;
const int N=2e5+,inf=0x3f3f3f3f;
int a[N],L[N],R[N],n,ans;
struct nd {
int x,y;
bool operator<(const nd& b)const {return x!=b.x?x<b.x:y<b.y;}
};
set<nd> st; int main() {
int T;
for(scanf("%d",&T); T--;) {
st.clear();
st.insert({,});
st.insert({inf,inf});
ans=;
scanf("%d",&n);
for(int i=; i<n; ++i)scanf("%d",&a[i]);
for(int l=,r; l<n; l=r) {
for(r=l+; r<n&&a[r]>a[r-]; ++r);
for(int j=l; j<r; ++j)L[j]=j-l+,R[j]=r-j;
}
for(int i=; i<n; ++i) {
set<nd>::iterator it,it2;
it=st.lower_bound({a[i],-}),it--;
ans=max(ans,it->y+R[i]);
st.insert({a[i],L[i]});
it=st.find({a[i],L[i]});
while() {
it2=it,it2++;
if(it2->y<=it->y)st.erase(it2);
else break;
}
it2=it,it2--;
if(it2->y>=it->y)st.erase(it);
}
printf("%d\n",ans);
}
return ;
}

第二种方法是每扫到一个i,直接查询a[j]<a[i]的元素中最大的L,怎么查呢?用树状数组(BIT)呗!树状数组不仅能动态维护前缀和,还能动态维护所有小于k的元素中的最大值哦!(当然,前提是没有将元素减小的操作)将原序列离散化后的值作为下标插入BIT中就行了,注意下标要从1开始。

 #include<bits/stdc++.h>

 using namespace std;
typedef long long ll;
const int N=2e5+,inf=0x3f3f3f3f;
int a[N],b[N],c[N],L[N],R[N],n,nn,ans;
int lowbit(int x) {return x&-x;}
void add(int u,int x) {for(; u<=nn; u+=lowbit(u))c[u]=max(c[u],x);}
int get(int u) {int ret=; for(; u; u-=lowbit(u))ret=max(ret,c[u]); return ret;} int main() {
int T;
for(scanf("%d",&T); T--;) {
ans=;
scanf("%d",&n);
for(int i=; i<n; ++i)scanf("%d",&a[i]),b[i]=a[i];
sort(b,b+n);
nn=unique(b,b+n)-b;
for(int i=; i<n; ++i)a[i]=lower_bound(b,b+nn,a[i])-b+;
for(int l=,r; l<n; l=r) {
for(r=l+; r<n&&a[r]>a[r-]; ++r);
for(int j=l; j<r; ++j)L[j]=j-l+,R[j]=r-j;
}
memset(c,,sizeof c);
for(int i=; i<n; ++i) {
ans=max(ans,R[i]+get(a[i]-));
add(a[i],L[i]);
}
printf("%d\n",ans);
}
return ;
}

第三种方法是最简洁最高效但也是最抽象的一种方法,就是仿照求LIS的算法,维护一个单调的数组c,记录所有L值为i的元素中最小的a[i](和BIT正好相反),每扫到一个元素a[i],在c中通过二分查找到比a[i]小的最大的元素,它的下标值就是最大的L,然后令c[L[i]]=min(c[L[i]],a[i])即可。其实这种方法和方法一原理是相同的,由于这道题比较特殊——L值是连续的!因为假设出现了某个L值,则L-1一定要出现在它前面,以此类推,因此不会出现下标空缺的现象,完全可以用数组来代替set。

 #include<bits/stdc++.h>

 using namespace std;
typedef long long ll;
const int N=2e5+,inf=0x3f3f3f3f;
int a[N],c[N],L[N],R[N],n,ans; int main() {
int T;
for(scanf("%d",&T); T--;) {
ans=;
scanf("%d",&n);
for(int i=; i<n; ++i)scanf("%d",&a[i]);
for(int l=,r; l<n; l=r) {
for(r=l+; r<n&&a[r]>a[r-]; ++r);
for(int j=l; j<r; ++j)L[j]=j-l+,R[j]=r-j;
}
memset(c,inf,sizeof c);
c[]=;
for(int i=; i<n; ++i) {
ans=max(ans,int(R[i]+lower_bound(c,c+n,a[i])-c-));
c[L[i]]=min(c[L[i]],a[i]);
}
printf("%d\n",ans);
}
return ;
}

虽然这种题已经做过n遍了,但做完之后还是有很大的感悟,里面蕴含的思想真的不容小觑啊。

UVA - 1471 Defense Lines (set/bit/lis)的更多相关文章

  1. UVA 1471 Defense Lines 防线 (LIS变形)

    给一个长度为n的序列,要求删除一个连续子序列,使剩下的序列有一个长度最大的连续递增子序列. 最简单的想法是枚举起点j和终点i,然后数一数,分别向前或向后能延伸的最长长度,记为g(i)和f(i).可以先 ...

  2. UVA - 1471 Defense Lines 树状数组/二分

                                  Defense Lines After the last war devastated your country, you - as the ...

  3. Uva 1471 Defense Lines(LIS变形)

    题意: 给你一个数组,让你删除一个连续的子序列,使得剩下的序列中有最长上升子序列, 求出这个长度. 题解: 预处理:先求一个last[i],以a[i]为开始的合法最长上升子序列的长度.再求一个pre[ ...

  4. UVa 1471 Defense Lines - 线段树 - 离散化

    题意是说给一个序列,删掉其中一段连续的子序列(貌似可以为空),使得新的序列中最长的连续递增子序列最长. 网上似乎最多的做法是二分查找优化,然而不会,只会值域线段树和离散化... 先预处理出所有的点所能 ...

  5. uva 1471 Defense Lines

    题意: 给一个长度为n(n <= 200000) 的序列,你删除一段连续的子序列,使得剩下的序列拼接起来,有一个最长的连续递增子序列 分析: 就是最长上升子序列的变形.需要加一个类似二分搜索就好 ...

  6. UVa 1471 Defense Lines (二分+set优化)

    题意:给定一个序列,然后让你删除一段连续的序列,使得剩下的序列中连续递增子序列最长. 析:如果暴力枚举那么时间复杂度肯定受不了,我们可以先进行预处理,f[i] 表示以 i 结尾的连续最长序列,g[i] ...

  7. uva 1471 defence lines——yhx

    After the last war devastated your country, you - as the king of the land of Ardenia - decided it wa ...

  8. 1471 - Defense Lines

    After the last war devastated your country, you - as the king of the land of Ardenia - decided it wa ...

  9. 【二分】Defense Lines

    [UVa1471] Defense Lines 算法入门经典第8章8-8 (P242) 题目大意:将一个序列删去一个连续子序列,问最长的严格上升子序列 (N<=200000) 试题分析:算法1: ...

随机推荐

  1. Django~1

    一 什么是web框架? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有 ...

  2. iOS Xcode 8 打包上架 配置文件问题 此构建版本无效 推送问题 攻克 刚刚 waiting for review

    煎熬...  本来xcode 7 打包正在审核了 还要修改一处购买问题  此时 xcode已经升级到xcode 8 了 升级后 很神奇 应用没报错 很好的运行 (网上很多说xib storyboard ...

  3. Redis之数据存储结构

    今天去中关村软件园面试,被问到:你做项目用到的Redis处理数据用的什么结构?顿时石化,”用到的结构,不就是key-value嘛,还有什么结构?“.面试官说:“平时除了工作,要加强学习,下面的面试我觉 ...

  4. matplotlib模块之子图画法

    一般化的子图布局 首先要创建各个子图的坐标轴,传入一个四元列表参数:[x,y,width,height],用来表示这个子图坐标轴原点的x坐标.y坐标,以及宽和高.值得注意的是,这四个值的取值范围都是[ ...

  5. Spring MVC 接收多个实体参数

    在SpringMVC 的接收参数中,如果接收一个实体对象,只需要在方法参数中这样做:@RequestBody User user //单个的时候这样接收 @RequestMapping(value = ...

  6. CCNA 课程 七

    WAN(Wide Area Network)广域网 运行在OSI模型的数据链路层.物理层. 数据链路层的协议主要有: HDLC  (High-Level Data Link Control 高级数据链 ...

  7. /var/spool/clientmqueue 爆满问题

    当你使用简单的sendmail发邮件的时候,或者系统默认要发一些邮件(比如cron发的邮件)的时候,首先会把邮件拷贝到这个目录里,然后等待MTA(mail transfer agent) 来处理,MT ...

  8. spring boot 使用thymeleaf3.0以及thymeleaf的热部署

    spring boot 截止1.5.4,默认使用thymeleaf2.0,会有一些很蛋疼的地方比如xml格式之类的,具体哪些就不说了 -> 替换为3.0版本 pom中加入 <propert ...

  9. HDFS-文件写入API

    package com.zhen.hdfs; import java.io.BufferedInputStream; import java.io.FileInputStream; import ja ...

  10. HDFS相关概念

    数据块 每个磁盘都有默认的数据块大小,这是磁盘进行数据读写的最小单位.构建与单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的快.该文件系统块的大小可以使磁盘块的整数倍.文件系统块一般为几千字节,而 ...