题目
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。
现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。
注意:每种变化最多只有一个值发生变化。
在样例输入1中,所有的变化是
1 2 3
2 2 3
1 3 3
1 1 3
1 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:
3 3 3
3 2 3
选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求。
思路
显然的dp
dp[i]表示到第i个元素的时候,最优情况。
如果dp[i]可以有dp[j]转移而来,那么j需要满足以下两个条件:
- (a[j]<=mi[i])
- (mx[j]<=a[i])
然后考虑CDQ分治优化dp:
显然上面的转移是二维的,所以只要分别用排序和树状数组消维就行了。
代码
#include<bits/stdc++.h>
#define M 100005
using namespace std;
int n,m;
struct node{
int s,mi,mx,ans,id;
}A[M];
bool cmps(node a,node b){return a.s<b.s;}
bool cmpmi(node a,node b){return a.mi<b.mi;}
bool cmp(node a,node b){return a.id<b.id;}
struct BIT{
int C[M];
void add(int x,int d){
x++;
while(x<=M+1){
C[x]=max(C[x],d);
x+=(x&-x);
}
}
int sum(int x){
x++;int s=0;
while(x){
s=max(s,C[x]);
x-=(x&-x);
}
return s;
}
void clear(int x){
x++;
while(x<=M+1){
C[x]=0;
x+=(x&-x);
}
}
}T;
void CDQ(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
CDQ(l,mid);sort(A+mid+1,A+r+1,cmpmi);
for(int i=l,j=mid+1;j<=r;j++){
while(i<=mid&&A[i].s<=A[j].mi){
T.add(A[i].mx,A[i].ans);i++;
}
A[j].ans=max(A[j].ans,T.sum(A[j].s)+1);
}
sort(A+mid+1,A+r+1,cmp);
for(int i=l;i<=mid;i++)T.clear(A[i].mx);
CDQ(mid+1,r);
sort(A+l,A+r+1,cmps);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)A[i].mi=1e9,A[i].mx=-1e9,A[i].ans=1;
for(int i=1,x;i<=n;i++)scanf("%d",&x),A[i].s=x,A[i].mi=min(A[i].mi,x),A[i].mx=max(A[i].mx,x),A[i].id=i;
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
A[x].mx=max(A[x].mx,y);
A[x].mi=min(A[x].mi,y);
}
CDQ(1,n);
int ans=0;
for(int i=1;i<=n;i++)ans=max(ans,A[i].ans);
printf("%d
",ans);
return 0;
}