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=;
char fh[sj];
int n,k,a[sj],f[sj],dh[],temp,jg,jd;
void bj(int &x,int y)
{
x=x>y?x:y;
}
struct Tree
{
int l,r,jz;
}ds[*],xs[*];
void bt1(int x,int y,int z)
{
ds[x].l=y;
ds[x].r=z;
if(y==z) return;
int mid=(y+z)>>;
bt1(x<<,y,mid);
bt1((x<<)|,mid+,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)>>;
bt2(x<<,y,mid);
bt2((x<<)|,mid+,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)>>;
if(mid<y) return query1((x<<)|,y,z);
if(z<=mid) return query1(x<<,y,z);
return max(query1(x<<,y,mid),query1((x<<)|,mid+,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)>>;
if(mid<y) return query2((x<<)|,y,z);
if(z<=mid) return query2(x<<,y,z);
return max(query2(x<<,y,mid),query2((x<<)|,mid+,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)>>;
if(mid<z) update1((x<<)|,y,z);
if(z<=mid) update1(x<<,y,z);
ds[x].jz=max(ds[x<<].jz,ds[(x<<)|].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)>>;
if(mid<z) update2((x<<)|,y,z);
if(z<=mid) update2(x<<,y,z);
xs[x].jz=max(xs[x<<].jz,xs[(x<<)|].jz);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
bj(jd,a[i]);
}
for(int i=;i<=k;i++) cin>>fh[i];
bt1(,,jd);
bt2(,,jd);
for(int i=;i<=n;i++)
{
if(dh[a[i]]+>f[i]) f[i]=dh[a[i]]+;
if(a[i]!=jd)
{
temp=query1(,a[i]+,jd);
if(temp+>f[i]) f[i]=temp+;
}
if(a[i]!=)
{
temp=query2(,,a[i]-);
if(temp+>f[i]) f[i]=temp+;
}
temp=f[i]%k;
if(!temp) temp=k;
if(fh[temp]=='=') dh[a[i]]=f[i];
if(fh[temp]=='>') update1(,f[i],a[i]);
if(fh[temp]=='<') update2(,f[i],a[i]);
bj(jg,f[i]);
}
printf("%d",jg);
return ;
}
Monotonicity 2[POI2010]的更多相关文章
- [补档][Poi2010]Monotonicity 2
[Poi2010]Monotonicity 2 题目 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. 选出一个长度为L的子序列(不要求连续),要求这个子序列 ...
- BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】
BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...
- 【BZOJ2090/2089】[Poi2010]Monotonicity 2 动态规划+线段树
[BZOJ2090/2089][Poi2010]Monotonicity Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k].选出一个长度 ...
- [Poi2010]Monotonicity 2 线段树
这道题考试的时候先打了个dfs暴力.又打了个O(n²)的动规.然后竟然心血来潮拍了一下..明明知道过不去的...然后水了50分(20个测试点这么多啊啊啊啊). 因为它已经提前给你如果长度为i时下一位的 ...
- Poi2010 Monotonicity 2
树状数组优化dp 可以证明最优解一定是通过之前的最优转移过来的,所以每一个点只需要保存以该节点为结尾的最长长度即可 对于不同符号,等于号维护数组,大于小于维护树状数组 #include<cstd ...
- #14 [BZOJ2090/2089] [Poi2010]Monotonicity 2/Monotonicity
题解: 首先想到了标算..然后证明了一发是错的(事实证明很智障) 先说正确性比较显然的O(n^2)算法 令f[i][j]表示前i个物品,匹配到第j个括号,最大值是多少 g[i][j]表示前i个物品,匹 ...
- BZOJ2090 : [Poi2010]Monotonicity 2
设f[i]表示以i为结尾的最长的合法序列的长度,=号直接维护,<号和>号用两棵树状数组维护即可,时间复杂度$O(n\log n)$. #include<cstdio> #def ...
- bzoj2089&2090: [Poi2010]Monotonicity
双倍经验一眼题... f[i][1/2]表示以i结尾,当前符号应该是</>的最长上升子序列, 用BIT优化转移就好 =的话就不用说了吧= = #include<iostream> ...
- [BZOJ2090/2089] [Poi2010]Monotonicity 2/Monotonicity 树状数组优化dp
这个dp乍看不科学,仔细一看更不科学,所以作为一个执着BOY,我决定要造数据卡死波兰人民,但是我造着造着就......证出来了......... 这个就是把 < > =分开讨论每次找到f[ ...
随机推荐
- 20170422早会训话,ps:程序出现两次BUG,领导很生气
针对这种问题: 要讲3点 1.有没有拖团队后腿: 作为一名前端开发人员,对于前端开发的任务,我能够在第一时间完成,保证时间进度,但光做到这一点是不够的,不能只讲究任务,不考虑结果,会不会出现问题造成其 ...
- Java中的事件监听机制
鼠标事件监听机制的三个方面: 1.事件源对象: 事件源对象就是能够产生动作的对象.在Java语言中所有的容器组件和元素组件都是事件监听中的事件源对象.Java中根据事件的动作来区分不同的事件源对象,动 ...
- Vue 项目实战系列 (三)
我们继续前两节的开发.本节教程实现的效果如下: 效果很简单,但是实现起来却要用到Vue的很多知识,下面我们将一步一步的实现这个效果. 首先这些城市的信息都是从后台的server里面获取的,所以我们需要 ...
- El表达式取map值
map el表达取值 ${initMap['kehuList']}
- mysql 转义字符
在用户提交表单的时候,有的用户会提交一些特殊字符,比如单引号双引号,此时,如果直接按正常字符串插入数据库的话,可能会出现无法正确插入数据库 PDO::quote 转义mysql语句中的单引号和双引号 ...
- 常用PHP函数的封装
PHP获取文件扩展名(后缀) function getExtension($filename){ $myext = substr($filename, strrpos($filename, '.')) ...
- Kafka 源代码分析之LogSegment
这里分析kafka LogSegment源代码 通过一步步分析LogManager,Log源代码之后就会发现,最终的log操作都在LogSegment上实现.LogSegment负责分片的读写恢复刷新 ...
- SQL联表查询
数据库中最最常用的语法----select.简单的select语法很直白: select column from table where expression: 从((from)存储数据的地方(tab ...
- webpack教程(二)——webpack.config.js文件
首先我们需要安装一个webpack插件html-webpack-plugin,该插件的作用是帮助我们生成创建html入口文件.执行如下命令 npm install html-webpack-plugi ...
- intellij idea 常用快捷键让你事半功倍
为什么谈这个 工欲善其事必先利其器,键盘流是必须的,快捷键首当其冲,请收下!!! 常用快捷键列表 Live Templates 自定义代码模板 取消屏幕的翻转,可以使用ctrl+alt+左右,进行代码 ...