题意: 允许扣去一个连续子串的情况下,求剩下串的最长连续增长子串。 长度<= 200000. 数据大小: 1e9。
第一次使用离散化。其核心是: 利用数据个数相对较少,将N个数据建立与整数1~N的映射。 方法是, 先排序 ,再二分查早序号。
而线段树可以用来维护区间最大值, 这里是最大“没有间隔的连续子串长度”。
离散化和线段树只是用来优化的,下面解释一下算法主题:DP
个人认为动态规划最重要的是状态表示和状态转移。
① dp[ max_len ][ 2 ] ; dp[ i ][ 0 ] 表示以第 i 个数结尾的不含间隔的最长增长子串长度,dp[ i ][ 1 ]表示以第 i 个数结尾的含间隔的最长增长子串长度。
② dp [ i ][ 0 ]相对容易计算, dp[ i ][ 0 ] = a[ i ] > a [ i-1 ] ? dp[ i-1 ][ 0 ] + 1 : 1.
而dp[ i ][ 1 ]来自两方面: 一是继承了dp[ i-1 ][ 1 ]的间隔(此时a[ i ] > a[ i-1 ]),二是 a[ i ]的前面就是间隔 ,此时需要知道以 a[ x ] (a[ x ]<a[ i ] && x < i)结尾的连续子串的最大长度。
有个问题困惑了很久,如果找不到间隔怎么办? dp[ i ][ 1 ]是否失去了意义? 阳神一句精辟的话提醒了我: 不影响结果。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Lson (cur)<<1,L,mid
#define Rson (cur)<<1|1,mid+1,R
const int maxn=200050;
int dp[maxn][2],a[maxn],LiSan[maxn];
int N;
int Tree[maxn<<2];
int Find(int x){
int Low=1,High=N,mid;
while(Low<High){
mid=(Low+High)>>1;
if(LiSan[mid]>=x) High=mid;
else Low=mid+1;
}
return Low;
}
void update(int cur){
Tree[cur] = max (Tree[cur] , Tree[cur<<1]);
Tree[cur] = max (Tree[cur] , Tree[(cur<<1)|1]);
}
void Insert(int cur,int L,int R,int l,int r,int x){
if(l<=L && R<=r){
Tree[cur]=max(Tree[cur] , x); return ;
}
int mid=(L+R)>>1;
if(l<=mid) Insert(Lson,l,r,x);
if(r>mid) Insert(Rson,l,r,x);
update(cur);
}
int Query(int cur,int L,int R,int l,int r){
if(l<=L && R<=r){
return Tree[cur];
}
int mid=(L+R)>>1;
int ans=0;
if(l<=mid) ans=max(ans,Query(Lson,l,r));
if(r>mid) ans=max(ans,Query(Rson,l,r));
return ans;
}
int main()
{
//freopen("D:/input.txt","r",stdin);
//freopen("D:/output.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
memset(Tree,0,sizeof(Tree));
memset(dp,0,sizeof(dp));
scanf("%d",&N);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]); LiSan[i]=a[i];
}
sort(LiSan+1,LiSan+N+1);
int ans=0;
dp[1][0]=1; dp[1][1]=1;
int p=Find(a[1]);
Insert(1,1,N,p,p,1);
ans=max(ans,dp[1][0]), ans=max(ans,dp[1][1]);
for(int d=2;d<=N;d++){
dp[d][0] = a[d]>a[d-1] ? dp[d-1][0]+1 : 1;
p=Find(a[d]);
Insert(1,1,N,p,p,dp[d][0]);
if(a[d] > a[d-1]) dp[d][1]=dp[d-1][1]+1;
int tmp=0;
if(p>1) tmp=Query(1,1,N,1,p-1);
dp[d][1] = max(dp[d][1] , tmp+1);
ans=max(ans,dp[d][0]),ans=max(ans,dp[d][1]);
}
printf("%d\n",ans);
}
return 0;
}