Monotonicity 2[POI2010]

题目描述

给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。

 

输入

第一行两个正整数,分别表示N和K (N, K <= 500,000)。
第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。
第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。

 

输出

一个正整数,表示L的最大值。

 

样例输入

7 3
2 4 3 1 3 5 3
< > =

样例输出

6

提示

选出的子序列为2 4 3 3 5 3,相邻大小关系分别是< > = < >。

 

【题解】

    喜闻乐见的数据结构优化dp。看完了题,在演草纸上写了一句“动规吧?”,然后就把这句话放一边了。觉得二分应该能行,就写了个二分。怎么check呢?写了个dfs。后来跟wzz说这个事,大佬非常不理解地说:还不如直接深搜呢,白白地加个log。瞬间觉得好有道理啊,果然上午不知道干了些什么。

   下午听讲题,自己连O(n^2)的转移方程都没写出来,简直了。正解思路很清奇,f[i]表示到i这一位最长的子序列长度,有了长度符号就定下来了。不等号按符号维护线段树,等号直接拿数组标记一下。线段树的下标是a[i]的权值,内容是f[i]的权值,这样区间查询满足不等号的最大值就非常快了。得出f[i]之后推出下一位的符号,更新相应的线段树或数组即可。

    线段树是个好东西。上次方伯伯的玉米田用到了树状数组优化dp,这一次算是第二道数据结构优化dp。虽然在理论上来讲树状数组比线段树好打多了,可我始终还是更喜欢线段树。连续两天的dp题都是想过它是dp,但还是没按dp来做。学完一段时间以后dp能力下降得多了,想当初正在讲的时候也是不怕想正解的。原来以为自己不擅长数学和数据结构,现在看来dp也不是很行,集训要做的事还太多了啊。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sj=500010;
char fh[sj];
int  n,k,a[sj],f[sj],dh[1000010],temp,jg,jd;
void bj(int &x,int y)
{
    x=x>y?x:y;
}
struct Tree
{
    int l,r,jz; 
}ds[1000010*4],xs[1000010*4];
void bt1(int x,int y,int z)
{
     ds[x].l=y;
     ds[x].r=z;
     if(y==z)  return;
     int mid=(y+z)>>1;
     bt1(x<<1,y,mid);
     bt1((x<<1)|1,mid+1,z);
}
void bt2(int x,int y,int z)
{
     xs[x].l=y;
     xs[x].r=z;
     if(y==z)  return;
     int mid=(y+z)>>1;
     bt2(x<<1,y,mid);
     bt2((x<<1)|1,mid+1,z);
}
int query1(int x,int y,int z)
{
    if(ds[x].l==y&&ds[x].r==z) return ds[x].jz;
    int mid=(ds[x].l+ds[x].r)>>1;
    if(mid<y) return query1((x<<1)|1,y,z);
    if(z<=mid) return query1(x<<1,y,z);
    return max(query1(x<<1,y,mid),query1((x<<1)|1,mid+1,z));
}
int query2(int x,int y,int z)
{
    if(xs[x].l==y&&xs[x].r==z) return xs[x].jz;
    int mid=(xs[x].l+xs[x].r)>>1;
    if(mid<y) return query2((x<<1)|1,y,z);
    if(z<=mid) return query2(x<<1,y,z);
    return max(query2(x<<1,y,mid),query2((x<<1)|1,mid+1,z));
}
void update1(int x,int y,int z)
{
    if(ds[x].l==ds[x].r&&ds[x].r==z)
    {
          ds[x].jz=y;
          return;
    }
    int mid=(ds[x].l+ds[x].r)>>1;
    if(mid<z)  update1((x<<1)|1,y,z);
    if(z<=mid) update1(x<<1,y,z);
    ds[x].jz=max(ds[x<<1].jz,ds[(x<<1)|1].jz);
}
void update2(int x,int y,int z)
{
    if(xs[x].l==xs[x].r&&xs[x].r==z)
    {
          xs[x].jz=y;
          return;
    }
    int mid=(xs[x].l+xs[x].r)>>1;
    if(mid<z)  update2((x<<1)|1,y,z);
    if(z<=mid) update2(x<<1,y,z);
    xs[x].jz=max(xs[x<<1].jz,xs[(x<<1)|1].jz);
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    { 
      scanf("%d",&a[i]);
      bj(jd,a[i]);
    }
    for(int i=1;i<=k;i++) cin>>fh[i];
    bt1(1,1,jd);
    bt2(1,1,jd);
    for(int i=1;i<=n;i++)
    {
        if(dh[a[i]]+1>f[i]) f[i]=dh[a[i]]+1;
        if(a[i]!=jd)
        {
          temp=query1(1,a[i]+1,jd);
          if(temp+1>f[i]) f[i]=temp+1;
        }
        if(a[i]!=1)
        {
          temp=query2(1,1,a[i]-1);
          if(temp+1>f[i]) f[i]=temp+1;
        }
        temp=f[i]%k;
        if(!temp) temp=k;
        if(fh[temp]=='=') dh[a[i]]=f[i];
        if(fh[temp]=='>') update1(1,f[i],a[i]);
        if(fh[temp]=='<') update2(1,f[i],a[i]);
        bj(jg,f[i]);
    }
    printf("%d",jg);
    return 0;
}

 

 

 

posted @ 2017-07-28 20:26  moyiii  阅读(211)  评论(0编辑  收藏  举报