刚开始做的时候,我还是按往常直接简单dp去做
结果自然WA了
后来我仔细地分析了一下,在于这是o(n2)级别的算法,题目给了106的数据。
很明显,要是想AC就要用o(n)或者0(nlogn)级别的算法,于是我就看视频还有数了解到一种算法。
老师网站:
https://www.acwing.com/problem/content/video/898/
这种方法类似于贪心,然后就是让小的更小,大的更大,这样后面的数更好的找到一个最长递增子序列,然后模拟一下过程很容易理解,然后lower_bound过程我最开始是用插入实现的,以为是o(n)的算法,看了运行时间之后才知道这是o(n2)级别的算法,然后我的代码当时是这样写的
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int dp[N],m[N];
int g[N],mx=0,mmx=0;
int main(void)
{
int n,z=0;;
cin>>n;
m[0]=-0x3f3f3f3f;
for(int i=1;i<=n;i++) cin>>g[i];
for(int i=1;i<=n;i++)
{
if(g[i]>m[z])
m[++z]=g[i];
else
{
int j;
for(j=z;j>=1&&m[j]>g[i];j--);
if(m[j]!=g[i])
m[j+1]=g[i];
}
}
cout<<z;
}
运行时间看起来很快。
然后我用二分法找小于g[i]的最大的数去做了一遍
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int m[N];
int g[N],mx=0,mmx=0;
int main(void)
{
int n,z=0;
cin>>n;
m[0]=-0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
cin>>g[i];
if(g[i]>m[z])
m[++z]=g[i];
else
{
int l=0,r=z;
while(l<r)
{
int mid=l+r+1>>1;
if(m[mid]<g[i]) l=mid;
else r=mid-1;
}
m[r+1]=g[i];
}
}
cout<<z;
}
达到了最快时间
我用lower_bound实现了一下
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int m[N];
int g[N],mx=0,mmx=0;
int main(void)
{
int n,z=0;
cin>>n;
m[0]=-0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
cin>>g[i];
if(g[i]>m[z])
m[++z]=g[i];
else
{
int j=lower_bound(m+1,m+1+z,g[i])-m;
m[j]=g[i];
}
}
cout<<z;
}
时间情况