USETC 1501 Defence Linces(DP+线段树+离散化)

来源:互联网 发布:oracle数据库入门书籍 编辑:程序博客网 时间:2024/05/20 15:59

题目链接

题意: 允许扣去一个连续子串的情况下,求剩下串的最长连续增长子串。  长度<= 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,Rconst 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;}