# [HEOI2016/TJOI2016]序列

题目链接

戳这

Solution

首先考虑最暴力的dp
我们设:
\(f[i]\)表示选择\(i\)以后所能形成的满足条件的子序列的最大值
\(minx[i]\)表示\(i\)能转换为的最小值
\(maxx[i]\)表示\(i\)能转换为的最大值

于是转移的条件显然了:

  1. \(i>j\)
  2. \(minx[i]>=a[j]\)
  3. \(a[i]>=maxx[i]\)

对于暴力直接枚举j转移就好了,但却只有50分,想想正解。
条件很明显是三维偏序问题啊。我们可以随便用一些数据结构:
如: cdq分治,树套树什么的。这里就不详细介绍了

code

线段树+树状数组

#include<bits/stdc++.h>
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
struct node {
    int l,r,v;
} a[100001*100];
int tot,root[100010];
void update(int &k,int l,int r,int pos,int v) {
    if(k==0)
        k=++tot;
    a[k].v=max(a[k].v,v);
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    if(pos<=mid) update(a[k].l,l,mid,pos,v);
    else update(a[k].r,mid+1,r,pos,v);
}
int find(int k,int l,int r,int begin,int end) {
    if(k==0)
        return 0;
    if(l==begin&&r==end)
        return a[k].v;
    int mid=(l+r)>>1;
    if(end<=mid)
        return find(a[k].l,l,mid,begin,end);
    else if(begin>mid)
        return find(a[k].r,mid+1,r,begin,end);
    else return max(find(a[k].l,l,mid,begin,mid),find(a[k].r,mid+1,r,mid+1,end));
}
#define lowbit(x) (x&(-x))
void add(int x,int y,int v) {
    while(x<=100005)
        update(root[x],1,100005,y,v),x+=lowbit(x);
}
int sum(int x,int y) {
    int js=0;
    while(x)
        js=max(find(root[x],1,100005,1,y),js),x-=lowbit(x);
    return js;
}
int b[100010],minx[100010],maxx[100010];
int main() {
    int n=read(),m=read(),x,y,ans=0;
    for(int i=1; i<=n; i++)
        b[i]=minx[i]=maxx[i]=read();
    for(int i=1; i<=m; i++)
        x=read(),y=read(),maxx[x]=max(maxx[x],y),minx[x]=min(minx[x],y);
    for(int i=1; i<=n; i++) {
        int js=sum(minx[i],b[i])+1;
        ans=max(ans,js);
        add(b[i],maxx[i],js);
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/hbxblog/p/10253236.html

时间: 2024-10-08 22:42:38

# [HEOI2016/TJOI2016]序列的相关文章

洛谷P4093 [HEOI2016/TJOI2016]序列

题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 . 注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 3 1 2 4 选择子序列为原序列,即在任意一种变化中均为不降子序列在

洛谷 P4093 [HEOI2016/TJOI2016]序列

题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 . 注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 3 1 2 4 选择子序列为原序列,即在任意一种变化中均为不降子序列在

【[HEOI2016/TJOI2016]序列】

压行真漂亮 首先这肯定是一个\(dp\)了 设\(dp_i\)表示\(i\)结尾的最长不下降子序列的长度 显然我们要找一个\(j\)来转移 也就是\(dp_i=max(dp_j+1)\) 那么什么样的\(j\)满足条件呢 首先得是\(j<i\) 我们还注意到一个条件就是这个序列里最多也只有一个位置会发生变化 可能是\(i\)这个位置发生变化,那么显然需要满足对于任意的\(a_i\)都需要满足大于等于\(val_j\) 于是就有\(val_j<=min_i\) 自然也有可能是前面的\(j\)发生

题解 P4093 【[HEOI2016/TJOI2016]序列】

这道题原来很水的? noteskey 一开始以为是顺序的 m 个修改,然后选出一段最长子序列使得每次修改后都满足不降 这 TM 根本不可做啊! 于是就去看题解了,然后看到转移要满足的条件的我发出了黑人问号... 然后才发现原来是求的子序列是满足任意一次修改后不降... 于是列出两(san)个条件式子,就可以 CDQ 切掉了 QWQ \(j<i\) \(a_j<min_i\) \(max_j<a_i\) 这里的 max 和 min 就是某个位置上出现过的最 大/小 值 watch out

luogu4093 [HEOI2016/TJOI2016]序列

因为一个变化只会变化一个值,所以 \(dp[i]=max(dp[j])+1,j<i,maxval_j \leq a[i], a[j] \leq minval_i\) 发现跟二维数点问题挺像,树状数组套线段树爽一爽. #include <iostream> #include <cstdio> using namespace std; int n, m, zdz[100005], zxz[100005], a[100005], uu, vv, cnt, dp[100005], a

「luogu4093」[HEOI2016/TJOI2016]序列

写出dp方程,可以发现转移要满足一个三维偏序,那么可以处理三维偏序的方法优化. CDQ分治: cdq分治和树状数组是好伙伴~ 注意分治的顺序,要保证先求解出所有前驱状态. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100010; 4 int n,m,dp[N],maxn; 5 struct Node{ 6 int a,maxv,minv,id; 7 }node[N]; 8 int cmpa(const Node

[HEOI2016/TJOI2016]序列 CDQ分治

---题面--- 题解: 首先我们观察一下,如果一个点对(j, i), 要符合题中要求要满足哪些条件? 首先我们设 j < i 那么有: j < i max[j] < v[i] v[j] < min[i] (注意下面两个式子都是用的v[i],v[j],,,而不是i , j...之前因为这个问题纠结了很久,其实我也不知道我在纠结什么...) 这三个式子是不是很眼熟? 如果式子变成: j < i max[j] < max[i] min[j] < min[i] 是不是就

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]排序 题意 给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种, 0 l r 表示将区间 \([l,r]\) 的数升序排序. 1 l r 表示将区间 \([l,r]\) 的数降序排序. 询问 \(m\) 次操作后下标为 \(q\) 的数字. 思路 不看题解打死也想不出来系列 考虑二分答案. 设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,