题目链接:点击查看

题目大意:给出一个长度为 n 的序列,现在要求分成尽可能少的子段,且每个子段需要满足:

  1. 最大值与最小值的差值小于等于 s
  2. 子段长度大于等于 l

题目分析:dp[ i ] 代表的是前 i 个数字分成最少的子段个数,转移方程如下:

  1. dp[ i ] = dp[ j - 1 ] + 1:第 i 项单独一段
  2. dp[ i ] = dp[ j - 2 ] + 1:第 i 项与 i - 1 项组成一段
  3. ...
  4. dp[ i ] = dp[ 0 ] + 1:第 1 ~ i 项组成一段

显然是取上面合法的前驱的最小值用来维护 dp[ i ],因为需要满足条件一,又因为子串的长度与 delta ,也就是最大值与最小值的差,成反比,所以可以二分找到 dp[ j ] 的左端点 l,而 dp[ j ] 的右端点 r 同时也被条件二限制,此时的问题就转换成了求区间 [ l , r ] 内 dp 的最小值了,这里用线段树维护一下就好,总的来说需要维护两个线段树,因为维护 dp[ i ] 的过程中需要套上一个二分,所以总的时间复杂度为 O( nlog^2n )

代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;namespace Seg1
{struct Node{int l,r,mmin,mmax;}tree[N<<2];void build(int k,int l,int r){tree[k].l=l;tree[k].r=r;if(l==r){scanf("%d",&tree[k].mmax);tree[k].mmin=tree[k].mmax;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);}int query_min(int k,int l,int r){if(tree[k].l>r||tree[k].r<l)return inf;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmin;return min(query_min(k<<1,l,r),query_min(k<<1|1,l,r));}int query_max(int k,int l,int r){if(tree[k].l>r||tree[k].r<l)return -inf;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmax;return max(query_max(k<<1,l,r),query_max(k<<1|1,l,r));}
}namespace Seg2
{struct Node{int l,r,mmin;}tree[N<<2];void build(int k,int l,int r){tree[k].l=l;tree[k].r=r;tree[k].mmin=inf;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);}void update(int k,int pos,int val){if(tree[k].l==tree[k].r){tree[k].mmin=val;return;}int mid=tree[k].l+tree[k].r>>1;if(pos<=mid)update(k<<1,pos,val);elseupdate(k<<1|1,pos,val);tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);}int query(int k,int l,int r){if(l>r)return inf;if(tree[k].l>r||tree[k].r<l)return inf;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmin;return min(query(k<<1,l,r),query(k<<1|1,l,r));}
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n,s,len;scanf("%d%d%d",&n,&s,&len);Seg1::build(1,1,n);Seg2::build(1,0,n);Seg2::update(1,0,0);for(int i=1;i<=n;i++){int l=1,r=i,mark=-1;while(l<=r){int mid=l+r>>1;int delta=Seg1::query_max(1,mid,i)-Seg1::query_min(1,mid,i);if(delta<=s){mark=mid;r=mid-1;}else{l=mid+1;}}if(mark!=-1)Seg2::update(1,i,Seg2::query(1,mark-1,i-len)+1);}if(Seg2::query(1,n,n)==inf)puts("-1");elseprintf("%d\n",Seg2::query(1,n,n));return 0;
}

CodeForces - 487B Strip(线段树+dp+二分)相关推荐

  1. Codeforces 786B Legacy (线段树优化建图)

    Codeforces 786B Legacy (线段树优化建图) 题意:\(n\)个点,有\(3\)种连边操作:1.将\(u\)指向\(v\):2.将\(v\)指向编号在区间\([l,r]\)的点:3 ...

  2. P1295 [TJOI2011]书架(线段树dp)

    P1295 [TJOI2011]书架(线段树dp) 我好菜 先考虑普通dp: d p i = m i n ( d p j + m a x ( h j + 1 , h j + 2 - , h i ) ) ...

  3. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  4. CodeForces - 1557D Ezzat and Grid(线段树+dp)

    题目链接:点击查看 题目大意:给出 nnn 个 010101 串,现在问最少需要删掉多少个串,才能使得剩下的串拼起来是连通的 规定两个 010101 串是连通的,当且仅当存在至少一列,在两个串中都为 ...

  5. CodeForces - 1354D Multiset(线段树/二分)

    题目链接:点击查看 题目大意:规定在一个 multiset 中初始时有 n 个元素,随后有 m 次操作,每次操作给出一个 num: num > 0 时:向 multiset 中添加 num nu ...

  6. New Year and Old Subsequence CodeForces - 750E(线段树+矩阵dp)2019南昌icpc网络赛Hello 2019

    A string t is called nice if a string "2017" occurs in t as a subsequence but a string &qu ...

  7. Educational Codeforces Round 81 (Rated for Div. 2) E. Permutation Separation 线段树 + dp

    传送门 文章目录 题意: 思路: 题意: 给你一个打乱的排列,每个位置都各有一个价值,让你选择一个分界点,分成p1,p2,...,prp_1,p_2,...,p_rp1​,p2​,...,pr​和pr ...

  8. YbtOJ#463-序列划分【二分答案,线段树,dp】

    正题 题目链接:https://www.ybtoj.com.cn/problem/463 题目大意 给出长度为nnn的序列A,BA,BA,B.要求划分成若干段满足 对于任何i<ji<ji& ...

  9. Codeforces 1398 F. Controversial Rounds —— 线段树+dp

    This way 题意: 给你一个字符串,有些位置是已知的,有些是未知的,从位置1开始,如果有连续的0或者1大于等于k个,那么就算一轮游戏,然后0,1重新计数.问你当k=1~n的时候,游戏轮数最多是多 ...

最新文章

  1. Android自定义控件前导基础知识学习(一)——Canvas
  2. 范式青春er,寻找同行的你!
  3. [Python人工智能] 二十八.Keras深度学习中文文本分类万字总结(CNN、TextCNN、LSTM、BiLSTM、BiLSTM+Attention)
  4. 在.NET中执行Async/Await的两种错误方法
  5. 【Python 标准库学习】系统相关的参数和函数库 — sys
  6. 自定义字体 (暂不支持中文)
  7. javascript 编译与执行过程
  8. c++ 结构体中不同类型的初始值_Golang语言基础教程:结构体
  9. java请求响应中转_J2EE中的请求中转、重定向和包含关系
  10. c++中*是什么意思_int在python中什么意思
  11. wifi rssi 计算 距离_SKYLAB:蓝牙室内定位与WiFi室内定位的对比分析
  12. 【转】和菜鸟一起学linux之DBUS基础学习记录
  13. 新手如何学习单片机,一套很好的51单片机教程
  14. 独家 | 利用滴滴出行数据透视中国城市空间发展(附视频PPT)
  15. 中兴新支点操作系统_中兴新支点国产操作系统体验报告:使用流畅,性能稳定!...
  16. Win10系统中耳机插入前后面板均没有声音
  17. V 社秘密开发 Steam 跨系统兼容工具;甲骨文开源 GraphPipe,机器学习模型标准
  18. 让人着迷的 STP生成树协议
  19. 0到π/0到2π,sinⁿx、cosⁿx的定积分
  20. git 提交两次commit到同一分支,被糅合为一次Marge Request的解决方法:cherry-pick

热门文章

  1. 不停刷朋友圈的人_不停刷新闻、朋友圈、微信群的朋友,休息一下,看多了伤身!...
  2. SpringAMQP--FanoutExchange
  3. Gateway网关-全局过滤器
  4. 下游传递唯一序列号如何实现幂等性?
  5. (常用API)正则表达式邮箱地址验证
  6. Stream流中的常用方法_map
  7. SpringBoot profile配置
  8. java中ArrayList和LinkedList的区别
  9. 使用软碟通安装 CentOS Stream 会遇到哪些问题
  10. pytorch教程龙曲良11-15