题目描述
小明是蓝桥王国的骑士,他喜欢不断突破自我。
这天蓝桥国王给他安排了 N 个对手,他们的战力值分别为 a1,a2,...,an,且按顺序阻挡在小明的前方。对于这些对手小明可以选择挑战,也可以选择避战。
身为高傲的骑士,小明从不走回头路,且只愿意挑战战力值越来越高的对手。
请你算算小明最多会挑战多少名对手。
输入描述
输入第一行包含一个整数 N,表示对手的个数。
第二行包含 N 个整数 a1,a2,...,an,分别表示对手的战力值。
1\leq N \leq 3\times10^51≤N≤3×105,1\leq a_i \leq 10^91≤ai≤109。
输出描述
输出一行整数表示答案。
输入输出样例
示例 1
输入
6
1 4 2 2 5 6
输出
4
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
题解代码:
只要求长度,可以考虑维护一个单调递增的序列来优化。
我们可以维护一个单调递增的序列,每当当前元素比栈顶元素大,就直接压入栈,否则我们就在这序列中二分找到第一个比它大的元素将其替换,最后序列禅读就是最长上升子序列长度,但是不保证这个递增序列就是最长上升子序列
为什么这样贪心是可行的呢,不难证明,由于当前值比二分值小,并且当前值的位置在二分的值的后 面,那么二者只能取其一,我比你小,就意味着后面可以容纳更多可能的元素, 也就是为后面最优解更 新创造条件。
二分查找替换可以利用 lower_bound(*first,*last,var)
函数lower_bound()在first和last中的前闭后开区间,进行二分查找。返回从first开始的第一个大于或等于val的元素的地址。如果所有元素都小于val,则返回last的地址。注意:数组必须是排好序的数组。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int a[maxn],l[maxn];
int lis(int n){
int lengh=1;
l[0]=a[0];
for(int i=1;i<n;i++)
{
if(l[lengh-1]<a[i]) l[lengh++]=a[i];
else *lower_bound(l,l+lengh,a[i])=a[i]; //*lower_bound相当于l数组
}
return lengh;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
cout<<lis(n)<<endl;
}
方法二:
#include<bits/stdc++.h>
using namespace std;
const int N = 10001;
int a[N],dp[N];
int main()
{
int n; cin >> n;
for(int i=1; i<=n; i++) cin >> a[i];
int ans = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++)
{
//-----执行的是:dp[i]=max(dp[j]+1) 其中:0<j<i , Aj<Ai-----------------------------
int max = 0;
for(int j=1; j<i; j++)
if(dp[j] > max && a[j] < a[i])
max = dp[j];
dp[i] = max+1;
//----------------------------------
if(dp[i] > ans) ans = dp[i];
}
cout << ans << endl;
return 0;
}