Codeforces 526F 分治

说实话这题挺简单的(知道题解以后),但是一般人做的时候脑洞不大一点还不一定做得出来。
显然,题目可化简为:给定 N 个数的一个排列,问这个序列中有多少个子区间的数恰好是连续的。
进一步可以化为:有多少种情况使得,相邻的 k 个数中最大值和最小值的差小于等于 k-1。
大致有两种解法,一种是分治,一种是线段树。
这里主要讲一下分治的解法。
考虑分治,对于当前区间[L,R],记区间中点为 mid。当前区间的答案就是Ans[L..mid]+Ans[mid+1..R]+跨过中点的合法区间数,然后就分为两种情况了:
1.最小值和最大值在同侧。
2.最小值和最大值在异侧。
下面只考虑最值同在左,和最小值在左,最大值在右的情况。
因为其余两种是对称的。
对于最值同在左侧的情况,我们O(N)枚举左边界在哪,然后可以
计算出右边界的位置,在判断是否合法,统计答案。对于最小值在左侧,最大值在右侧的情况,如果一个区间满足我们所要求的关系的话,就一定有:
max(a[mid +1]…a[right]) - min(a[left]…a[mid]) =right- left
移项可得
max(a[mid +1]…a[right]) - right = min(a[left]…a[mid]) -left
然后可以用单调栈来完成这个任务。 如果加一些黑科技可以大大减少代码量,但是复杂度会多一个 log。
简单提一下,线段树解法的思路大致也是维护一个单调栈,然后进行区间修改和查询,统计答案。
蒟蒻还在用Pas,虽然偶尔也用C艹

uses math;
const maxn=300010;

var
    n,i,j,k,p,m,x:longint;
    maxm,minm,num:array[0..maxn]of longint;
    f:array[
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值