您的位置:首页 > 理论基础 > 计算机网络

hdu-5489(2015网络赛合肥赛区)***

2015-09-30 19:34 411 查看
题目链接

题意:给定一个长度为N<=105的序列
求删去连续长度为0<=L<=N的序列后的LIS

思路:

假设你已经会O(nlogn)的LIS, 删去i
前面连续一段长度为L
即[i−L,i-1]的
序列, 左边是i−L−1,
右边是i,
求剩下的LIS

首先预处理出:

f[i]:=以a[i]结尾的LIS的最大长度

g[i]:=以a[i]开头的LIS的最大长度

我们可以根据i,
找到 [0,i−L−1]之间的一个值

其值小于a[i],
而其f[i]值是最大的,
也就是O(n2)求LIS的思想

关键是如何快速确定在[0,i−L−1]中,
找到这个值

我们利用线段树和离散化, 将a[i]映射到线段树上

假设i位置对应的值是x,并且其映射到线段树上对应的下标是y

那么我们只要在线段树上查找[0,y−1]之间的最大值maxv

maxv[i]=max{f[j],j∈[0,i−L+1]∪a[j]<a[i]}

其实就是dp[i]:=以a[i]结尾,
删去[i−L,i−1]长度为L的LIS的最大长度

dp[i]=maxv[i]+g[i],ans=max{dp[i]}

注意:普通的LIS算法只能求得区间内的LIS但不能保证毕包含头或尾,

这里利用lower_bound函数在nlogn的时间求任意前缀且包含前缀尾的LIS ( 即f[ i ] )。

同样利用该函数求得任意后缀且包含后缀头的LIS ( 即g[ i ] )。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<stdio.h>
#include<math.h>
#include <string>
#include<string.h>
#include<map>
#include<queue>
#include<set>
#include<utility>
#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define eps 1e-8
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define ll long long int
#define mod 1000003
#define maxn 110000
#define maxm 10001005
int mi(int a,int b){return a<b?a:b;}
int ma(int a,int b){return a>b?a:b;}
int n,t,L,ans;
int a[maxn],aa[maxn];
int f[maxn],g[maxn],h[maxn];
int mx[maxn*4];
void update(int rt,int x,int v,int l,int r){
    if(l==r) {
        mx[rt]=ma(mx[rt],v);
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=x) update(rt*2,x,v,l,mid);
    else update(rt*2+1,x,v,mid+1,r);
    mx[rt]=ma(mx[rt*2],mx[rt*2+1]);
}
int query(int rt,int lx,int rx,int l,int r){
    if(l==lx&&r==rx) return mx[rt];
    int mid=(l+r)>>1;
    if(rx<=mid) return query(rt*2,lx,rx,l,mid);
    else if(lx>mid) return query(rt*2+1,lx,rx,mid+1,r);
    else {
        int lv=query(rt*2,lx,mid,l,mid);
        int rv=query(rt*2+1,mid+1,rx,mid+1,r);
        return ma(lv,rv);
    }
}
int main()
{
    rd(t);
    int tt=0;
    while(t--){
        rd2(n,L);
        for(int i=1;i<=n;i++){
            rd(a[i]);
            aa[i]=a[i];
        }
        sort(aa+1,aa+1+n);
        int nn=unique(aa+1,aa+1+n)-aa-1;
        memset(h,0x3f,sizeof h);
        for(int i=1;i<=n;i++){//求1~i的包含a[i]的LIS!!
            int k=lower_bound(h+1,h+1+n,a[i])-h;
            f[i]=k;
            h[k]=a[i];
        }
        memset(h,0x3f,sizeof h);
        for(int i=n;i>=1;i--){//求i~n的包含a[i]的LIS!!
            int k=lower_bound(h+1,h+1+n,-a[i])-h;
            g[i]=k;
            h[k]=-a[i];
        }
        a[0]=f[0]=g[n+1]=0; a[n+1]=0x3f3f3f3f;
        memset(mx,0,sizeof mx);
        ans=0;
        for(int i=L+1;i<=n+1;i++){
            int k=lower_bound(aa+1,aa+1+nn,a[i])-aa;
            int v=query(1,0,k-1,0,nn);
            ans=ma(ans,v+g[i]);
            k=lower_bound(aa+1,aa+1+nn,a[i-L])-aa;
            if(i<=n) update(1,k,f[i-L],0,nn);
        }
        printf("Case #%d: %d\n",++tt,ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: