题目链接
题意:
给定一长度为n的数列,请在不改变原数列顺序的前提下,从中随机的取出一定数量的整数,并使这些整数构成单调上升序列。 输出这类单调上升序列的最大长度。
数据范围:
1<=n<=1000001<=n<=100000
思路:
dp
代码:
正常求LIS的方法应该下面这种:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],dp[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
dp[i]=1;//将以a[i]结尾的最长上升子序列的长度设为1
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);//如果a[i]>a[j],说明a[j]可以加到以a[i]结尾的子序列后面
}
}
cout<<*max_element(dp+1,dp+1+n)<<endl;//取最大值
return 0;
}
但是这道题数据有点大,所以要用其他方法,具体看代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],d[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int len=1;d[1]=a[1];
for(int i=1;i<=n;i++)
{
if(a[i]>d[len])//如果a[i]大于目前最长上升子序列的最优结尾,那么长度加一,结尾替换
{
len++;
d[len]=a[i];//这里的d[N]数组记录的是长度为len的上升子序列的最优结尾
}
else//如果新出现的a[i]小于目前最长上升子序列的最优结尾
{
d[lower_bound(d+1,d+len+1,a[i])-d]=a[i];//二分查找将该结尾放到最优的位置,替换掉前面比他大的最优结尾,成为最优结尾
}
}
cout<<len<<endl;
}