首先,容易得到判断一个子串为“good k-d sequence”的方法:

  • 子串中没有重复元素,且所有元素模d相等。
  • 记mx为除以d的最大值,mn为除以d的最小值,则\(mx-mn<=r-l+k\)。

然后,我们对于每一段极大的元素同模的子串,处理\(d=1\)的情况。

显然,我们需要枚举一个端点。这里,我们从大到小枚举左端点。(当然,从小到大枚举右端点也是可行的)

我们使用单调栈和线段树,可以维护每个位置\(mx-mn\)的值。然后,因为对于每一个位置,\(r\)是固定的,所以我们把\(r\)移到左边。即有不等式\(mx-mn-r<=k-l\)。

然后,我们需要确定最右边的\(mx-mn-r<=k-l\)的元素位置,这个线段树上二分就可以了。

最后还有两个细节:

  • 为避免出现重复元素,线段树上二分时有限制。
  • 特判\(d=0\)的情况。

时间复杂度\(O(nlogn)\)。

#include <bits/stdc++.h>
using namespace std;
const int BAS = 1e9, N = 200010;
struct node {
int mn,tag;
inline void operator += (int x) {
mn += x;
tag += x;
}
inline void reset() {
mn = tag = 0;
}
} t[N << 2];
void push_down(int x) {
t[x<<1] += t[x].tag;
t[x<<1|1] += t[x].tag;
t[x].tag = 0;
}
void push_up(int x) {
if (t[x].tag) push_down(x);
t[x].mn = min(t[x<<1].mn,t[x<<1|1].mn);
}
void modify(int x,int l,int r,int v,int lp,int rp) {
if (lp > r || rp < l) return;
if (lp >= l && rp <= r)
return (void)(t[x] += v);
int mid = (lp + rp) >> 1;
modify(x<<1,l,r,v,lp,mid);
modify(x<<1|1,l,r,v,mid+1,rp);
push_up(x);
}
int dfs(int x,int lim,int v,int lp,int rp) {
if (t[x].mn > v) return -1;
if (lp == rp) return lp;
push_down(x);
int mid = (lp + rp) >> 1;
if (t[x<<1|1].mn <= v && mid + 1 <= lim) {
int res = dfs(x<<1|1,lim,v,mid+1,rp);
if (~res) return res;
}
return dfs(x<<1,lim,v,lp,mid);
}
int n,k,d,arr[N],len;
map<int,int> mp;
int tmp[N];
struct data_sta {
int l,r,val;
inline bool operator < (const data_sta& x) const {
return val < x.val;
}
} st[2][N];
int top[2];
struct data_ans {
int l,r;
inline bool operator < (const data_ans& x) const {
return r - l + 1 != x.r - x.l + 1 ? \
r - l + 1 > x.r - x.l + 1 : l < x.l;
}
};
data_ans solve() {
mp.clear();
data_sta tp;
data_ans res = (data_ans) {len,-1};
int cur = len, rec;
top[0] = top[1] = 0;
for (int i = len ; i >= 1 ; -- i) {
if (mp[tmp[i]]) cur = min(cur,mp[tmp[i]] - 1);
mp[tmp[i]] = i;
tp = (data_sta) {i,i,tmp[i]};
while (top[0] && st[0][top[0]].val < tp.val) {
modify(1,st[0][top[0]].l,st[0][top[0]].r,-st[0][top[0]].val,1,len);
tp.r = st[0][top[0]--].r;
}
st[0][++top[0]] = tp;
modify(1,tp.l,tp.r,tp.val,1,len);
tp = (data_sta) {i,i,tmp[i]};
while (top[1] && st[1][top[1]].val > tp.val) {
modify(1,st[1][top[1]].l,st[1][top[1]].r,st[1][top[1]].val,1,len);
tp.r = st[1][top[1]--].r;
}
st[1][++top[1]] = tp;
modify(1,tp.l,tp.r,-tp.val,1,len);
modify(1,i,i,-i,1,len);
rec = dfs(1,cur,k - i,1,len);
if (~rec) res = min(res,(data_ans) {i,rec});
}
for (int i = 1 ; i <= (len << 2) ; ++ i)
t[i].reset();
return res;
}
int special_solve() {
int res = 0, p = -1;
for (int i = 1, j; i <= n ; i += j) {
j = 1;
while (arr[i+j] == arr[i] && i + j <= n) ++ j;
if (res < j) res = j, p = i;
}
printf("%d %d\n",p,p + res - 1);
return 0;
}
int main() {
scanf("%d%d%d",&n,&k,&d);
for (int i = 1 ; i <= n ; ++ i)
scanf("%d",&arr[i]), arr[i] += BAS ;
if (d == 0) return special_solve();
data_ans res = (data_ans) {1,1}, tp;
for (int i = 1, j ; i <= n ; i += j) {
j = 1;
while (arr[i+j] % d == arr[i] % d && i + j <= n)
++ j;
len = j;
for (int s = 0 ; s < j ; ++ s)
tmp[s+1] = arr[i+s] / d;
tp = solve();
tp.l += i-1, tp.r += i-1;
res = min(res,tp);
}
printf("%d %d\n",res.l,res.r);
return 0;
}

小结:这样一类题目大概就是要怼着式子简化问题。

【做题】CF239E. k-d-sequence——线段树的更多相关文章

  1. 2016暑假多校联合---Rikka with Sequence (线段树)

    2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta i ...

  2. Wow! Such Sequence!(线段树4893)

    Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...

  3. HDU 6047 Maximum Sequence(线段树)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=6047 题目: Maximum Sequence Time Limit: 4000/2000 MS (J ...

  4. Codeforces 438D The Child and Sequence - 线段树

    At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at ...

  5. ZOJ 4100 浙江省第16届大学生程序设计竞赛 A题 Vertices in the Pocket 线段树+并查集

    正赛的时候完全没看这个题,事后winterzz告诉我他想出来的解法. 首先题意是给出n个点,m次操作. 操作有一种是连接两个点,另一种是求此时再为这个图连k条边,最少和最多能有几个联通块. 最少的求法 ...

  6. Codeforces 486E LIS of Sequence(线段树+LIS)

    题目链接:Codeforces 486E LIS of Sequence 题目大意:给定一个数组.如今要确定每一个位置上的数属于哪一种类型. 解题思路:先求出每一个位置选的情况下的最长LIS,由于開始 ...

  7. K - Japan(线段树)

    Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Jap ...

  8. 【BZOJ】3038: 上帝造题的七分钟2(线段树+暴力)

    http://www.lydsy.com:808/JudgeOnline/problem.php?id=3038 这题我就有得吐槽了,先是线段树更新写错,然后不知哪没pushup导致te,精度问题sq ...

  9. Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸

    D. The Child and Sequence Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest ...

  10. codevs2492上帝造题的七分钟 2(线段树)

    /* 区间修改 区间查询 可以用线段树搞 但是一般的标记下放对这个题好像不合适 只能改叶子 然后更新父亲(虽然跑的有点慢) 小优化:如果某个点是1 就不用再开方了 所以搞一个f[i]标记 i 这个点还 ...

随机推荐

  1. sql server case

    use mytest go exec p_city 2,4 exec p_city_cnt 2,3 select stuff((select ',' + city_id from cities for ...

  2. 事件响应模型(游戏引擎、JAVA中等应用)

    事件,我们在生活中时时在产生事件并且做出响应,如早晨出门时,看见外面下雨了,这时候我们需要带把伞等情况! 在现实生活之中事件分为人为事件和自然事件,那么在计算机操作系统中也不例外,存在两种事件 1.人 ...

  3. 类模板中的static关键字

    特性: 1.从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员 2. 和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定 ...

  4. MVC 翻頁的那些坑

    思绪良久,最后还是决定记录一下遇到的坑,毕竟被 ‘折磨’ 了三天,关于分页,这个话题,我一开始时拒绝的,因为真正接触项目的时候,才发现每个框架都会封装一套自己的分页,毕竟相同风格的项目是不常见的,而在 ...

  5. 关于Weex你需要知道的一切

    QCon第一天,GMTC全球移动技术大会联席主席.手淘技术老大庄卓然(花名南天)在Keynote上宣布跨平台开发框架Weex开始内测,并将于6月份开源,同时他们也放出官网:http://alibaba ...

  6. ymPrompt,jcs缓存架构

    jcs.auxiliary.LTCP=org.apache.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory#jcs.auxiliary. ...

  7. バイナリハックイージー / Unhappy Hacking (ABC Edit) (stack)

    题目链接:http://abc043.contest.atcoder.jp/tasks/abc043_b Time limit : 2sec / Memory limit : 256MB Score ...

  8. 自学Java第二周的总结

    在这一周里我在网上学习了java的对象和类,了解了对象与类以及简单的用法.对象是类的一个实例(对象不是找个女朋友),有状态和行为.例如,一条狗是一个对象,它的状态有:颜色.名字.品种:行为有:摇尾巴. ...

  9. 前端框架VUE----webpack打包工具的使用

    在这里我仅仅的是对webpack做个讲解,webpack这个工具非常强大,解决了我们前端很繁琐的一些工具流程繁琐的事情.如果感兴趣的同学,还是看官网吧. 中文链接地址:https://www.webp ...

  10. Java 持久化操作之 --XML

    摘自:http://www.cnblogs.com/lsy131479/p/8728767.html 1)有关XML简介 XML(EXtensible Markup Language)可扩展标记语言 ...