hdu 4604 Deque,树状数组,最长上升/下降子序列
正在补习13多校题。
给你一组数,按顺序取出来,再给一个deque,按顺序把这组数取出来插到deque中,可以插头和尾,也可以直接丢掉。
要求deque中元素非降。
问deque中元素最多有多少个。
只要枚举一个中心点,然后就是找这个点之后的大于这个元素的最长上升序列和小于这个元素的下降序列的长度和+1,更新答案即可。
这里有一个蛋疼的地方,数组中元素是可能重复的(看样例还以为1到n,尼玛),还需要离散化。
而且不能简单的选大于等于和小于等于的数的和。
这样,从后面往前面做,i=n..1,设第i个点值为v
可能更新答案的只有
([v+1..n]中上升序列长度最长的)+([1..v]中下降序列长度最长的)+1
([v..n]中上升序列长度最长的)+([1..v-1]中下降序列长度最长的)+1
这两种。
这样可以省去找最长点的位置。
至于找[1..v]间的最大值,用树状数组简短实用。
正在补习13多校题。
给你一组数,按顺序取出来,再给一个deque,按顺序把这组数取出来插到deque中,可以插头和尾,也可以直接丢掉。
要求deque中元素非降。
问deque中元素最多有多少个。
只要枚举一个中心点,然后就是找这个点之后的大于这个元素的最长上升序列和小于这个元素的下降序列的长度和+1,更新答案即可。
这里有一个蛋疼的地方,数组中元素是可能重复的(看样例还以为1到n,尼玛),还需要离散化。
而且不能简单的选大于等于和小于等于的数的和。
这样,从后面往前面做,i=n..1,设第i个点值为v
可能更新答案的只有
([v+1..n]中上升序列长度最长的)+([1..v]中下降序列长度最长的)+1
([v..n]中上升序列长度最长的)+([1..v-1]中下降序列长度最长的)+1
这两种。
这样可以省去找最长点的位置。
至于找[1..v]间的最大值,用树状数组简短实用。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define NN 101000
#define lowbit(x) (x&(-x))
int c[2][NN];
int ans,n;
int a[NN];
int b[NN];
int tn;
int bsch(int l,int r,int val){
int m;
while(l<=r){
m=l+r>>1;
if (val==b[m]) return m;
else if (val<b[m]){
r=m-1;
}
else l=m+1;
}
}
int getmax(int pos,int c[]){
int ret=0;
while(pos){
ret=max(ret,c[pos]);
pos=pos-lowbit(pos);
}
return ret;
}
void add(int pos,int val,int c[]){
while(pos<=n){
c[pos]=max(c[pos],val);
pos+=lowbit(pos);
}
}
void work(int i){
int v,m0,m1,m2,m3;
v=a[i];
m0=getmax(v-1,c[0]);
m1=getmax(n-v,c[1]);
m2=getmax(v,c[0]);
m3=getmax(n+1-v,c[1]);
ans=max(m0+m3+1,ans);
ans=max(m1+m2+1,ans);
add(v,m2+1,c[0]);
add(n+1-v,m3+1,c[1]);
}
int main(){
//freopen("4604in.txt","r",stdin);
int cas,i;
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=a[i];
}
tn=1;
sort(b+1,b+n+1);
for(i=2;i<=n;++i){
if (b[i]!=b[i-1]) b[++tn]=b[i];
}
for(i=1;i<=n;++i){
a[i]=bsch(1,tn,a[i]);
}
ans=0;
memset(c,0,sizeof(c));
for(i=n;i>=1;--i){
work(i);
}
printf("%d\n",ans);
}
return 0;
}