LIS:最长上升子序列;

这个题我们很显然会想到使用dp,

状态设计:dp[i]代表以a[i]结尾的LIS的长度 
状态转移:dp[i]=max(dp[i], dp[j]+1) (0<=j< i, a[j]< a[i]) 
边界处理:dp[i]=1 (0<=j< n) 
时间复杂度:O(N^2) 

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
using namespace std;
const int MAXN=;
int n,a[MAXN],dp[MAXN];
int LIS()
{
int ans=;
for(int i=;i<=n;i++)
{
dp[i]=;
for(int j=;j<i;j++)
if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+);
ans=max(ans,dp[i]);
}
return ans;
}
int main()
{
n=read();
for(int i=; i<=n; i++)
cin>>a[i];
int ans=LIS();
cout<<ans<<endl;
return ;
}

但是n^2的做法显然会超时,所以介绍一种二分优化的做法;

用二分+贪心的思想可以将时间复杂度优化至(nlogn);

a[i]表示第i个原数据。 
dp[i]表示表示长度为i+1的LIS结尾元素的最小值。 
利用贪心的思想,对于一个上升子序列,当前添加的最后一个元素越小,越有利于添加新的元素,这样LIS长度更长。 
因此,我们只需要维护dp数组,其表示的就是长度为i+1的LIS结尾元素的最小值,保证每一位都是最小值,

这样子dp数组的长度就是LIS的长度。

这样每次查找就用到了我们的stl函数撒;

介绍一下upper_boundlower_bound;

(刚知道这个东西)

lower_bound( )和upper_bound( )是利用二分查找的方法在一个有序的数组中进行查找的。

当数组是从小到大时,

lower_bound( begin,end,num):表示从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,找到数字在数组中的下标。

upper_bound( begin,end,num):表示从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,找到数字在数组中的下标。

当数组是从大到小时,我们需要重载lower_bound()和upper_bound();

struct cmp{bool operator()(int a,int b){return a>b;}};

lower_bound( begin,end,num,cmp() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num,cmp() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

所以我们就可以使用stl函数寻找lis啦;

针对上面那个题:

#include<bits/stdc++.h>
using namespace std;
#define N 500001
inline int read()
{
int x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
int n,a[N],l[N];
struct cmp{bool operator()(int a,int b){return a>b;}};
int main()
{
n=read();
for(int i=;i<=n;i++) a[i]=read();
int con=,cont=;
l[]=a[];
for(int i=;i<=n;i++)
{
if(l[cont]<a[i]) l[++cont]=a[i];
else l[upper_bound(l+,l+cont+,a[i])-l]=a[i];
}
cout<<cont<<endl;
return ;
}

所以我们想一下有没有什么dp的题可以用stl写呢?

嗯...导弹拦截,这个题可以完美的体现stl的好处;

luogu

这个题我们需要求出最长单调不升子序列和一个最长单调上升子序列;

这个题两种写法,学了stl后又写了一个,明显stl代码短很多;

因为洛谷输入和本校oj不太一样,酌情修改代码...

#include<bits/stdc++.h>
using namespace std;
int a[],f[],l[],n;
struct cmp{bool operator()(int a,int b){return a>b;}};
int main()
{
// int n=1;
// while(cin>>a[n]) n++;
// n--;
cin>>n;
for(int i=;i<=n;i++) cin>>a[i];
int con=,cont=;
l[]=f[]=a[];
for(int i=;i<=n;i++)
{
if(l[cont]>=a[i])l[++cont]=a[i];
else l[upper_bound(l+,l+cont+,a[i],cmp())-l]=a[i];
if(f[con]<a[i])f[++con]=a[i];
else f[lower_bound(f+,f+con+,a[i])-f]=a[i];
}
cout<<cont<<endl<<con;
return ;
}
/*
#include<iostream>
using namespace std;
int n;
int h[1001],ht[1001],best[1001];
int ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>h[i];
best[0]=0x7fffffff;
for(int i=1;i<=n;i++)
for(int j=ans;j>=0;j--)
if(best[j]>=h[i])
{
best[j+1]=h[i];
ans=max(ans,j+1);
break;
}
cout<<ans<<endl;
ans=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=ans;j++)
{
if(ht[j]>=h[i])
{
ht[j]=h[i];
break;
}
}
if(ht[ans]<h[i])ht[++ans]=h[i];
}
cout<<ans;
return 0;
}*/

看了好多手写二分的都快一二百行了,可是我还不会啊...

所以懒,写了stl函数,才知道代码的精短,核心不到十行;

总结:寻找最长上升(使用lower_bound)和最长不下降时(使用upper_bound),无需重载;

寻找最长下降(使用lower_bound)和最长不上升时(使用upper_bound),需重载;

#include<bits/stdc++.h>
using namespace std;
const int N=7e5+;
template<typename T>inline void read(T &x)
{
x=;T f=,ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
x*=f;
}
long long n,f[N],s[N],t[N],l[N],a[N],ans1,ans2,ans3,ans4;
struct cmp{bool operator()(int a,int b){return a>b;}};
int main()
{
read(n);
for(int i=;i<=n;i++)
read(a[i]);
l[]=f[]=s[]=t[]=a[];
ans1=ans2=ans3=ans4=;
for(int i=;i<=n;i++)
{
if(f[ans1]<a[i]) f[++ans1]=a[i];
else f[lower_bound(f+,f+ans1+,a[i])-f]=a[i];
if(s[ans2]>a[i]) s[++ans2]=a[i];
else s[lower_bound(s+,s+ans2+,a[i],cmp())-s]=a[i];
if(t[ans3]>=a[i]) t[++ans3]=a[i];
else t[upper_bound(t+,t+ans3+,a[i],cmp())-t]=a[i];
if(l[ans4]<=a[i]) l[++ans4]=a[i];
else l[upper_bound(l+,l+ans4+,a[i])-l]=a[i];
}
printf("%lld\n%lld\n%lld\n%lld\n",ans1,ans2,ans3,ans4);
return ;
}

二分优化lis和STL函数的更多相关文章

  1. 分治算法(二分查找)、STL函数库的应用第五弹——二分函数

    分治算法:二分查找!昨天刚说不写算法了,但是突然想起来没写过分治算法的博客,所以强迫症的我…… STL函数库第五弹——二分函数lower_bound().upper_bound().binary_se ...

  2. 二分优化的lis

    /*此题为一个女大佬教我的,%%%%%%%%%%%%*/ 题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为 ...

  3. POJ 3903:Stock Exchange(裸LIS + 二分优化)

    http://poj.org/problem?id=3903 Stock Exchange Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  4. HDU 1025 LIS二分优化

    题目链接: acm.hdu.edu.cn/showproblem.php?pid=1025 Constructing Roads In JGShining's Kingdom Time Limit: ...

  5. HDU 1025:Constructing Roads In JGShining's Kingdom(LIS+二分优化)

    http://acm.hdu.edu.cn/showproblem.php?pid=1025 Constructing Roads In JGShining's Kingdom Problem Des ...

  6. (LIS)最长上升序列(DP+二分优化)

    求一个数列的最长上升序列 动态规划法:O(n^2) //DP int LIS(int a[], int n) { int DP[n]; int Cnt=-1; memset(DP, 0, sizeof ...

  7. STL函数库的应用第四弹——全排列(+浅谈骗分策略)

    因为基础算法快学完了,图论又太难(我太蒻了),想慢慢学. 所以暂时不写关于算法的博客了,但又因为更新博客的需要,会多写写关于STL的博客. (毕竟STL函数库还是很香的(手动滑稽)) 请出今天主角:S ...

  8. 51Nod 1090 3个数和为0 set 二分优化

    给出一个长度为N的无序数组,数组中的元素为整数,有正有负包括0,并互不相等.从中找出所有和 = 0的3个数的组合.如果没有这样的组合,输出No Solution.如果有多个,按照3个数中最小的数从小到 ...

  9. hdu5256 二分求LIS+思维

    解题的思路很巧,为了让每个数之间都留出对应的上升空间,使a[i]=a[i]-i,然后再求LIS 另外二分求LIS是比较快的 #include<bits/stdc++.h> #define ...

随机推荐

  1. NTSC PAL 介绍

    NTSC-J是日本地区的模拟 电视系统和视频显示标准,于2011年7月24日在全国47个县中的44个地区停止运营.模拟广播于2012年3月31日在2011年Tōhoku摧毁的三个县停止地震和海啸(岩手 ...

  2. Python 学习笔记3 变量-数字

    我们来具体了解下有关 number类型的变量的使用方式和含义. 在Python中的Number类型的变量包含以下几种: int: 通常我们所说的整数, 比如 1, 2 ,3 ,100, 3000 等等 ...

  3. ItunesConnect:"Missing Push Notification Entitlement"警告-----以及解决方法

    最近开发的cordova应用,要做ios的适配,并且发布版本,但是有一次在发测试版本的时候,突然收到一封邮件警告,原文如下: Missing Push Notification Entitlement ...

  4. java iso8859 转utf8

    http://www.it1352.com/110853.html https://blog.csdn.net/RR369_yyh/article/details/77582441 /* 输出 下面这 ...

  5. Schlumberger Petrel 2016.3 地震解释 油藏模拟

    Schlumberger Petrel 2016.3 地震解释 油藏模拟世界上顶尖的三维地质建模软件,软件为用户提供的工具可以用于地震解释.地质建模.油藏数 值模拟等方面的使用,清晰的地质模型可以描述 ...

  6. PyTorch常用代码段整理合集

    PyTorch常用代码段整理合集 转自:知乎 作者:张皓 众所周知,程序猿在写代码时通常会在网上搜索大量资料,其中大部分是代码段.然而,这项工作常常令人心累身疲,耗费大量时间.所以,今天小编转载了知乎 ...

  7. spring-data-radis错误

    org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested ...

  8. #WEB安全基础 : HTTP协议 | 0x16 HTTPS:证书,证书,全是证书

    现在想做点什么事都需要证书,要不就会让我们回忆起一个典故:滥竽充数 HTTPS使用了公开密钥加密,如何保证公开密钥就是真正的公开密钥呢?攻击者可能会替换公开密钥,这时候就需要验证,所以它采用了数字证书 ...

  9. 微信小程序如何实现点击链接跳转到手机自带浏览器

    最近遇到一个需求.公司有一个业务,制作的小程序需要跳出微信打开一个指定的我们自己的页面,拿到这个需求后我们团队分开去找资料研究方案,通过微信的开发文档.腾讯的第三方开发文档我们都查阅过资料但是最终只找 ...

  10. Java利用原始HttpURLConnection发送http请求数据小结

    1,在post请求下,写输出应该在读取之后,否则会抛出异常. 即操作OutputStream对象应该在InputStreamReader之前. 2.conn.getResponseCode()获取返回 ...