给一个长度为n的序列,要求删除一个连续子序列,使剩下的序列有一个长度最大的连续递增子序列。

最简单的想法是枚举起点j和终点i,然后数一数,分别向前或向后能延伸的最长长度,记为g(i)和f(i)。可以先预处理出每一个点能往前和往后延伸的长度(g(i)和f(i))。然后枚举终点i,快速找一个g(j)最大的起点。如果有两个候选的起点,一个j,一个j‘,A[j']<=A[j]且g[j']>g[j],那么j一定可以排除,g(j')更大,而且更容易拼接。

固定i的情况下,所有有价值的(A[j],g(j))按照A[j]排序(A[j]相同的值保留g(j)大的那个),将会形成一个有序表,根据之前的结论g(j)是递增的,有序,那么二分查找就派上用处了。

然后再考虑,变动i对之前的有序表的影响,i增加,把之前的A[i],g(i)加入到有序表中,如果满足A[i']比它A[i]小且g(i')最大的二元组,即它前面的一个元素,满足g(i')>=g(i),那么这个元素不该保留。否则应该加入这个二元组,加入这个二元组之后,为了保持有序表的性质,还要往后检查删除一些g(i*)小的元素。

终于想得比较透彻了,实现方式是set,用pair来保证二元组,pair比较的时候是先比较第一维,相等时才比较第二维。至于第二种实现,用数组保存g(j)对应最小的A[j]值,复习LIS时再补上吧~

#include<bits/stdc++.h>
#define MP make_pair
#define se second
#define fi first
using namespace std;
const int maxn = 2e5+;
typedef pair<int,int> pii;
int A[maxn];
int g[maxn];//<-
int f[maxn];//->
//set<pii> s;
map<int,int> s; int main()
{
int T; scanf("%d",&T);
while(T--){
int n; scanf("%d",&n);
for(int i = ; i < n; i++) scanf("%d",A+i);
if(n == ) { printf("1\n"); continue; }
g[] = ;
for(int i = ; i < n; i++) {
if(A[i]>A[i-]) g[i] = g[i-]+;
else g[i] = ;
}
f[n-] = ;
for(int i = n-; i >= ; i--) {
if(A[i]<A[i+]) f[i] = f[i+]+;
else f[i] = ;
}
s.clear(); s.insert(MP(A[],g[]));
int ans = ;
for(int i = ; i < n; i++){
//pii cur(A[i],g[i]);
map<int,int>::iterator it = s.lower_bound(A[i]);
bool keep = true;
if(it!=s.begin()){
it--;
ans = max(ans,it->se+f[i]);
keep = it->se < g[i];
}
if(keep){
//s.erase(cur);
it = s.insert({A[i],g[i]}).fi;
it++;
while(it != s.end() && it->se <= g[i] ) s.erase(it++);
}
}
printf("%d\n",ans);
}
return ;
}

set_插入前要erase,因为set里的元素是不支持修改的,insert的返回值是itertor,bool

#include<bits/stdc++.h>
#define MP make_pair
#define se second
#define fi first
using namespace std;
const int maxn = 2e5+;
typedef pair<int,int> pii;
int A[maxn];
int g[maxn];//<-
int f[maxn];//->
set<pii> s; int main()
{
int T; scanf("%d",&T);
while(T--){
int n; scanf("%d",&n);
for(int i = ; i < n; i++) scanf("%d",A+i);
if(n == ) { printf("1\n"); continue; }
g[] = ;
for(int i = ; i < n; i++) {
if(A[i]>A[i-]) g[i] = g[i-]+;
else g[i] = ;
}
f[n-] = ;
for(int i = n-; i >= ; i--) {
if(A[i]<A[i+]) f[i] = f[i+]+;
else f[i] = ;
}
s.clear(); s.insert(MP(A[],g[]));
int ans = ;
for(int i = ; i < n; i++){
pii cur(A[i],g[i]);
set<pii>::iterator it = s.lower_bound(cur);
bool keep = true;
if(it!=s.begin()){
it--;
ans = max(ans,it->se+f[i]);
keep = it->se < cur.se;
}
if(keep){
s.erase(cur);
it = s.insert(cur).fi;
it++;
while(it != s.end() && it->se <= cur.se ) s.erase(it++);
}
}
printf("%d\n",ans);
}
return ;
}

类似LIS的写法,非常简洁的感觉

#include<bits/stdc++.h>
using namespace std; const int maxn = 2e5+;
int f[maxn],g[maxn];//前,后
int a[maxn];
int v[maxn];
const int INF = 0x3f3f3f3f; int main()
{
int Z; cin>>Z;
while(Z--){
int n; scanf("%d",&n);
for(int i = ; i < n; i++) scanf("%d",a+i);
f[] = ;
for(int i = ; i < n; i++)
f[i] = + (a[i] > a[i-] ? f[i-] : ); g[n-] = ;
for(int i = n-; i--; )
g[i] = + (a[i] < a[i+] ? g[i+] : ); int ans = ;
for(int i = ; i < n; i++){
v[+i] = INF;
int k = lower_bound(v+,v++i,a[i])-v-;
ans = max(ans,k+g[i]);
v[f[i]] = min(v[f[i]],a[i]);
}
printf("%d\n",ans);
}
return ;
}

UVA 1471 Defense Lines 防线 (LIS变形)的更多相关文章

  1. Uva 1471 Defense Lines(LIS变形)

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

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

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

  3. UVA - 1471 Defense Lines (set/bit/lis)

    紫薯例题+1. 题意:给你一个长度为n(n<=200000)的序列a[n],求删除一个连续子序列后的可能的最长连续上升子序列的长度. 首先对序列进行分段,每一段连续的子序列的元素递增,设L[i] ...

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

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

  5. uva 1471 Defense Lines

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

  6. UVALive 4976 Defense Lines ——(LIS变形)

    题意:给出序列,能够从这序列中删去连续的一段,问剩下的序列中的最长的严格上升子串的长度是多少. 这题颇有点LIS的味道.因为具体做法就是维护一个单调的集合,然后xjbg一下即可.具体的见代码吧: #i ...

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

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

  8. uva 1471 defence lines——yhx

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

  9. 1471 - Defense Lines

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

随机推荐

  1. 7.19实习培训日志- java进阶

    java进阶 java集合 Collection List ArrayList jdk1.2,异步处理,性能高,线程不安全 Vector jdk1.0,同步处理,性能低,线程安全 Set HashSe ...

  2. HRBUST - 1214 NOIP2000提高组 方格取数(多线程dp)

    方格取数 设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放人数字0.如下图所示(见样例 ,黄色和蓝色分别为两次走的路线,其中绿色的格子为黄色和蓝色共同走过的 ...

  3. Celery 基本使用

    1. 认识 Celery Celery 是一个 基于 Python 开发的分布式异步消息任务队列,可以实现任务异步处理,制定定时任务等. 异步消息队列:执行异步任务时,会返回一个任务 ID 给你,过一 ...

  4. null, undefined 和布尔值

    说明:此类博客来自以下链接,对原内容做了标注重点知识,此处仅供自己学习参考! 来源:https://wangdoc.com/javascript/basic/introduction.html 1.n ...

  5. sqlserver的语句和mysql语句

    感谢原创 sqlserver和mysql基本语句的对比 http://blog.csdn.net/kk185800961/article/details/47044751 sqlserver中常见的语 ...

  6. 使用Xilinx SDSoc在Xilinx zcu102开发板上编程HelloWorld

    关于Xilinx SDSoc的介绍我就不再复述了,我理解的也不一定准确,可以阅读官方文档了解SDSoc,你可以把它理解为一个集成开发环境 (IDE),通过SDSoc我们能够简单快速的对Xilinx的开 ...

  7. Git提交与恢复

    Git提交与恢复 提交修改 git add --all # 提交所有修改文件 git add file file # 提交部分修改文件 $ git status On branch master Yo ...

  8. CreateJS介绍-了解CreateJS

    1.CreateJS 一款HTML5游戏开发引擎 CreateJS 是一套可以构建丰富交互体验的 HTML5 游戏的开源工具包,旨在降低 HTML5 项目的开发难度和成本,让开发者以熟悉的方式打造更具 ...

  9. 2017"百度之星"程序设计大赛 - 初赛(A)小C的倍数问题

    Problem Description 根据小学数学的知识,我们知道一个正整数x是3的倍数的条件是x每一位加起来的和是3的倍数.反之,如果一个数每一位加起来是3的倍数,则这个数肯定是3的倍数. 现在给 ...

  10. hdu1494 跑跑卡丁车(动态规划)

    Description 跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣.这款游戏的特别之处是你可以通过漂移来获得一种 加速卡,用这种加速卡可以在有限的时间里提高你的速度. ...