超级好的最长子序列DP元问题,而且还考核了需要做到(nlogn)的优化;
题目连接:
题目大意:
1 一个长度是10W的数列,分别求最长不上升子序列 和 最长上升子序列 ;
2 如果能进将时间复杂度优化到(nlogn),附赠100分!
解题思路1:100分(朴素思维:O(n*n)):
1 DP套路1:问什么设什么:
1.1 对于问题1:f[i]表示:以 i 开头的最长不上升子序列的长度值;
1.2 对于问题2:f[i]表示:以 i 结尾的最长上升子序列的长度值;
2 DP套路2:设前面的任务完成了,i的值和谁有关?
2.1 对于任何一个 i 而言,他前面的每个 j 都和他有关,所以这是一个 n方的询问;
3 DP套路3:初始状态,每个序列最长都是1,所以f[i]值初始化为1。
上代码(朴素版本的:100分):
//luogu1020:导弹拦截
//解法1:简单DP:O(n*n)
//求一个最长不上升子序列,再求一个最长上升子序列
#include<bits/stdc++.h>
using namespace std;
const int mx=1e5+10;
int n=0,s1=0,s2=0,f[mx],a[mx];
int main()
{
while(scanf("%d",&a[++n])!=EOF);
n--;
for(int i=n;i>=1;i--)//以 i 开头的,最长不上升
{
f[i]=1;
for(int j=i+1;j<=n;j++)
{
if(a[j]<=a[i])
{
f[i]=max(f[i],f[j]+1);
}
}
s1=max(s1,f[i]);//求出最长的
}
for(int i=1;i<=n;i++)//以 i 结尾,的最长上升
{
f[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]<a[i])
{
f[i]=max(f[i],f[j]+1);
}
}
s2=max(s2,f[i]);
}
printf("%d\n%d",s1,s2);
return 0;
}