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;
}
时间: 2024-10-11 21:56:07

Monotonicity 2[POI2010]的相关文章

【BZOJ2090/2089】[Poi2010]Monotonicity 2 动态规划+线段树

[BZOJ2090/2089][Poi2010]Monotonicity Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k].选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1].求出L的最大值. Input 第一行两个正整数,分别表示N和K (N, K <= 500,000).第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6).第三行给出K

[Poi2010]Monotonicity 2 (线段树优化DP)

题目描述 给出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的

[补档][Poi2010]Monotonicity 2

题目 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. 选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]. 求出L的最大值. INPUT 第一行两个正整数,分别表示N和K (N, K <= 500,000). 第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6). 第三行给出K个空格隔开关系符号(>.<或=),第i个表示s[i]. OUTPUT 一

BZOJ2090 : [Poi2010]Monotonicity 2

设f[i]表示以i为结尾的最长的合法序列的长度,=号直接维护,<号和>号用两棵树状数组维护即可,时间复杂度$O(n\log n)$. #include<cstdio> #define N 1000000 int n,k,i,j,a[N],e[N+1],bl[N+1],bg[N+1],f[N],ans;char s[N]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<

[Poi2010]Monotonicity 2题解

题目描述 给出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的

BZOJ 2090 [Poi2010]Monotonicity 2 DP+线段树

题意: 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. 选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]. 求出L的最大值. 解析: 一眼考虑DP,不过这个DP我的确刚开始认为这是没有什么正确性的,然后我就不会辣,但是大家都说这题就是DP.. 并且好像自己一顿想要构造也没有构造出来不合法的数据? 那我就只能回到自己刚开始的DP思路了. 设F[i]表示到第i位拿出来的最长序列长度. 所以下一个符

ural 1346. Intervals of Monotonicity

1346. Intervals of Monotonicity Time limit: 1.0 secondMemory limit: 64 MB It’s well known that a domain of any continuous function may be divided into intervals where the function would increase monotonically or decrease monotonically. A number of in

单调队列 BZOJ 2096 [Poi2010]Pilots

2096: [Poi2010]Pilots Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 819  Solved: 418[Submit][Status][Discuss] Description Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值.耍畸形一个人是不行的,于是他找到了你. Input 输入:第一行两个有空格隔开的整数k(0

BZOJ 2086: [Poi2010]Blocks

2086: [Poi2010]Blocks Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 494  Solved: 222[Submit][Status][Discuss] Description 给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1.经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数