挑战LIS (二分 加 正反遍历)
来源:互联网 发布:vue main.js引入less 编辑:程序博客网 时间:2024/05/17 00:14
对于一个数的序列a1,a2...an,当满足a1<a2<...<an时,我们定义这样的序列是严格递增(上升)的序列。我们还可以从这个序列中抽出部分数字(至少1个)
并按原有顺序排列,组成新的序列,我们称之为一个子序列。
最长上升子序列(Longest Increasing Subsequence,LIS)是一个非常经典的问题,它是指一个序列中最长且严格递增的子序列。
对于求一个已知序列的LIS的长度,我们有一个非常易懂的方法。
设原有序列a的长度为n,定义f[i]表示从a[1]至a[i],且以a[i]为结尾最长上升子序列的长度,
则f[i](1<=i<=n)可以由以下的C++代码计算
for (int i=1; i<=n; i++) {
int maxValue=0;
for (int j=1; j<=i-1; j++) {
if (a[j]<a[i]&&f[j]>maxValue) {
maxValue=f[j];
}
}
f[i]=maxValue+1;
}
最终在f[i] (1<=i<=n)中取最大值,我们便可以得到LIS的长度。
现在,我们不止对最长上升子序列的长度感兴趣,并且想要知道对于原有序列中的每个数是否属于某个最长上升子序列。输入格式
多组输入数据
每组数据第一行为一个数n,(1<=n<=999)表示原序列的长度
下一行为n个整数(在int范围内),分别是a1至an。
输出
每组数据分为两行输出,第一行为一个整数L,表示原序列的最长上升子序列的长度。
第二行为n个连续的数字,若原序列某个数字不属于任意最长上升子序列,则输出数字1;若属于某个最长上升子序列则输出数字2。
样例输入
3
1 2 3
4
3 4 2 5
5
111 16 -73 11 9
样例输出
3
222
3
2212
2
11222
#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<map>#include<queue>#include<math.h>#include<stack>using namespace std;#define LL long long#define mp(a,b) make_pair((a),(b))#define clr(x,a) memset(x,a,sizeof(x))#define INF 0x3f3f3f3f#define lb(x) ((x)&(-x))#define rep(i,a,b) for(int i=a;i<=b;i++)const int N=1005,siz=1e9;const int MOD=1e9+7;int n;int gcd(int x,int y){ return y==0?x:gcd(y,x%y);}int a[1005];int f[1005],g[1005],dp[1005];int solve(int len,int x){ int l=1,r=len+1; int ret; while(l<=r){ int m=(l+r)>>1; if(l==len+1) return len+1; if(x>=dp[m]){ ret=m; r=m-1; }else{ l=m+1; } } return ret;}int main(){ //freopen("aaa.txt","r",stdin); //freopen("bbb.txt","w",stdout); while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ scanf("%d",&a[i]); } clr(f,0); clr(g,0); clr(dp,0); f[0]=1; int len=1; dp[1]=a[0]; for(int i=1;i<n;i++){ f[i]=lower_bound(dp+1,dp+len+1,a[i])-dp; dp[f[i]]=a[i]; if(f[i]>len) len=f[i]; } int ans=len; g[n-1]=1; clr(dp,0); dp[1]=a[n-1]; len=1; for(int i=n-2;i>=0;i--){ g[i]=solve(len,a[i]); if(g[i]>len) len=g[i]; dp[g[i]]=a[i]; }// for(int i=0;i<n;i++) cout<<f[i];// cout<<endl;// for(int i=0;i<n;i++) cout<<g[i];// cout<<endl; cout<<len<<endl; for(int i=0;i<n;i++){ if(g[i]+f[i]==ans+1) cout<<2; else cout<<1; } cout<<endl; } return 0;}
- 挑战LIS (二分 加 正反遍历)
- LIS之贪心加二分,,求最大长---记录路径(待检验--欢迎提供数据)
- hdoj--5532--Almost Sorted Array(正反LIS)
- poj 3670 (LIS+二分查找)
- POJ 1631 Bridging signals(LIS+二分)
- POJ1836 Alignment 【LIS(二分)+枚举】
- LIS的O(nlogn)算法(二分)
- 二分图(挑战程序设计竞赛)
- 二分图判定 (挑战程序设计竞赛)
- 高精度加二分(二分有坑点)
- HDOJ 5532 Almost Sorted Array (正反LIS判断顺序)
- zoj 11986 LIS 二分
- poj3670,LiS(二分查找)
- LIS 二分加速版
- 合唱队形 LIS 二分
- LIS-二分查找模版
- 用二分做LIS
- 双向链表(插入,删除,追加,正反向遍历,查找。。。)
- 用 Addr2line 将函数地址解析为函数名
- read与write方法
- java—IO流
- 大整数模板
- Eclipse启动时failed to load the jni shared library
- 挑战LIS (二分 加 正反遍历)
- selenium-python-LocatingByXPath
- 03-OC中的分类(Category),代码块(Block),协议(property)
- 04-OC中的Foundation框架
- Android之选项卡
- 【剑指Offer面试编程题】题目1354:和为S的连续正数序列--九度OJ
- page、request、session、application的使用及区别
- 05-OC中NSString常见方法
- nyoj 33 蛇形填数