http://acm.hdu.edu.cn/showproblem.php?pid=4604
把一个序列中的元素放到队列里面,有3种操作,对于第i个元素
1.放到队头2.放到队尾3.舍弃
求最长上升序列的长度
法1:求出每个以a[i]为起点的最长不升子序列的长度,和最长不降子序列的长度,两个相加再减去a[i]重复的次数
法2:把当前序列复制两个,一个逆序,求总共的最长上升子序列的长度,然后奇偶避免重复
//法1
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#define foreach(v) (v).begin(),(v).end()
#define pk push_back
const int maxn = 100010;
using namespace std;
int num[maxn];
int down[maxn],up[maxn],down_same[maxn],up_same[maxn];
int n;
vector<int> vi;
void solve(int dp[],int same[])
{
vi.clear();
for(int i=n;i>=1;--i){
int a=lower_bound(foreach(vi),num[i])-vi.begin();
int b=upper_bound(foreach(vi),num[i])-vi.begin();
if(b==vi.size()||vi.empty()){
vi.pk(num[i]);
dp[i]=vi.size();
}else{
vi[b]=num[i];
dp[i]=b+1;
}
same[i]=b-a+1;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&num[i]);
}
solve(down,down_same);
for(int i=1;i<=n;++i){
num[i]=-num[i];
}
solve(up,up_same);
int ans=0;
for(int i=1;i<=n;++i){
ans=max(ans,up[i]+down[i]-min(up_same[i],down_same[i]));
}
printf("%d\n",ans);
}
return 0;
}
//法2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#define foreach(v) (v).begin(),(v).end()
#define pk push_back
const int maxn = 100010;
using namespace std;
int a[maxn];
int n;
vector<int> vi;
void solve(int x)
{
int b=upper_bound(foreach(vi),x)-vi.begin();
if(b==vi.size()||vi.empty())
vi.pk(x);
else
vi[b]=x;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
vi.clear();
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
for(int i=n;i>=1;--i){
solve(2*a[i]+1);
}
for(int i=1;i<=n;++i){
solve(2*a[i]);
}
printf("%d\n",vi.size());
}
return 0;
}
时间: 2024-11-19 18:41:19