题意:给定$a_{1\cdots n}$,让你求出一个最长的子串$a_{l\cdots r}$,使得这个子串加上最多$k$个数字并排序后是一个公差为$d$的等差数列

首先$d=0$就是最长连续相等段,扫一遍解决

然后显然$a_{l\cdots r}$都是模$d$同余的,我们不妨对模$d$的余数不同的段分开处理

把每个数先$+10^9$(让它变为非负)再除以$d$,转化为$d=1$的问题

那么题目的限制条件就是$\mathop\max\limits_{i=l}^ra_i-\mathop\min\limits_{i=l}^ra_i+1\leq r-l+1+k$且$a_{l\cdots r}$中没有重复元素

所以整个算法的大致思路就是,对$a_{l\cdots r}$,从大到小枚举$i\in[l,r]$,找到最大的$j\in[l,r]$满足$\mathop\max\limits_{k=i}^ja_k-\mathop\min\limits_{k=i}^ja_k-r\leq k-l$且$a_{i\cdots j}$中没有相同元素

没有相同元素:直接用一个map存每个数上一次出现的位置,相应左移$r$即可

对于这个不等式,注意到$f(r)=\mathop\max\limits_{i=l}^ra_i$是单调不减的,所以我们可以用一个单调栈存当前区间内对于不同的$j$,对上式有贡献的$a_i$(即从左往右扫,会令当前最大值变化的那些$a_i$),$\min$同理,当左端点移动时,入栈出栈的同时用线段树维护$\max-\min$即可,对于$-r$,建线段树时第$i$位的初值赋为$-i$即可,我们只需要在线段树上二分找到最右的$\leq k-i$的值即可

#include<stdio.h>
#include<map>
using namespace std;
int mn[800010],ad[800010];
void add(int x,int v){
	mn[x]+=v;
	ad[x]+=v;
}
void pushdown(int x){
	if(ad[x]){
		add(x<<1,ad[x]);
		add(x<<1|1,ad[x]);
		ad[x]=0;
	}
}
void pushup(int x){mn[x]=min(mn[x<<1],mn[x<<1|1]);}
void build(int l,int r,int x){
	if(l==r){
		mn[x]=-l;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	pushup(x);
}
void modify(int L,int R,int v,int l,int r,int x){
	if(L<=l&&r<=R)return add(x,v);
	pushdown(x);
	int mid=(l+r)>>1;
	if(L<=mid)modify(L,R,v,l,mid,x<<1);
	if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
	pushup(x);
}
int query(int L,int R,int v,int l,int r,int x){
	if(mn[x]>v)return 0;
	if(l==r)return l;
	pushdown(x);
	int mid=(l+r)>>1,res;
	if(R>mid){
		res=query(L,R,v,mid+1,r,x<<1|1);
		if(res)return res;
	}
	if(L<mid){
		res=query(L,R,v,l,mid,x<<1);
		if(res)return res;
	}
	return 0;
}
map<int,int>pos;
int a[200010],s1[200010],s2[200010],n,k,d,t1,t2,L,R;
void solve(int l,int r){
	if(l==r)return;
	int i,tr,res;
	for(i=l;i<=r;i++)a[i]=a[i]/d+1;
	tr=r+1;
	pos.clear();
	t1=t2=0;
	s1[0]=s2[0]=r+1;
	for(i=r;i>=l;i--){
		if(pos.count(a[i]))tr=min(tr,pos[a[i]]);
		while(t1&&a[i]>a[s1[t1]]){
			modify(s1[t1],s1[t1-1]-1,-a[s1[t1]],1,n,1);
			t1--;
		}
		t1++;
		s1[t1]=i;
		modify(s1[t1],s1[t1-1]-1,a[i],1,n,1);
		while(t2&&a[i]<a[s2[t2]]){
			modify(s2[t2],s2[t2-1]-1,a[s2[t2]],1,n,1);
			t2--;
		}
		t2++;
		s2[t2]=i;
		modify(s2[t2],s2[t2-1]-1,-a[i],1,n,1);
		res=query(i,tr-1,k-i,1,n,1);
		if(res-i>R-L||(res-i==R-L&&i<L)){
			L=i;
			R=res;
		}
		pos[a[i]]=i;
	}
}
int main(){
	int i,l,r;
	scanf("%d%d%d",&n,&k,&d);
	for(i=1;i<=n;i++){
		scanf("%d",a+i);
		a[i]+=1000000000;
	}
	L=R=1;
	if(d==0){
		for(l=1;l<=n;l=r){
			for(r=l;r<=n&&a[r]==a[l];r++);
			if(r-l>R-L+1){
				L=l;
				R=r-1;
			}
		}
		printf("%d %d",L,R);
		return 0;
	}
	build(1,n,1);
	L=R=1;
	for(l=1;l<=n;l=r){
		for(r=l;r<=n&&a[l]%d==a[r]%d;r++);
		solve(l,r-1);
	}
	printf("%d %d",L,R);
}

[CF407E]k-d-sequence的更多相关文章

  1. 【dfs】Sequence Decoding

    Sequence Decoding 题目描述 The amino acids in proteins are classified into two types of elements, hydrop ...

  2. Gym 100703G---Game of numbers(DP)

    题目链接 http://vjudge.net/contest/132391#problem/G Description standard input/outputStatements — It' s ...

  3. 转:Python获取随机数(中文)

    下面介绍下random中常见的函数. 前提:需要导入random模块 >>>import random 1.random.random random.random() 用于生成一个0 ...

  4. Qt4--加密日记本(子例化QMainWindow文本加密解密)

    近来刚学习Qt4编程,想找个实例练习练习,于是产生了一个想法,就是怎么样做一个文本加密,这样,自己保存的一些文档可以通过软件 生成加密文本,到时候要看的时候,通过自己的软件读取就可以.既然有想法了,那 ...

  5. python随机数

    前提:需要导入random模块 >>>import random 1.random.random random.random()用于生成一个0到1的随机符小数: 0 <= n ...

  6. 关于python 模块导入

    如何将自己写的库加入到python的库路径中: 首先查看python包含的库路径,步骤如下: a.打开python命令界面 b.import  sys    c.sys.path 1.在python安 ...

  7. 剑指Offer 23. 二叉搜索树的后序遍历序列 (二叉搜索树)

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 题目地址 https://www.nowcoder ...

  8. 开发笔记:python与随机数(转)

    这些天需要用到从一堆数中随机提取几个数,于是重新研究了下random模块. 下面介绍下random中常见的函数. 前提:需要导入random模块 >>>import random 1 ...

  9. Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力)

    Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力) 题目描述 如果一个数组1.至少三个元素2.两两之间差值相同,那么这个数组就是算术序列 比如下面的数组都是算 ...

  10. python随机数的产生

    导入 random模块  >>> import random 1.  random.random random.random()用于生成一个0到1的随机浮点数: 0 <= n ...

随机推荐

  1. 自己模拟实现一下Google的赛马Doodle

    今天的Google Doodle是个动态的,是一个骑马的动态Doodle,是谷歌纪念英国实验摄影师埃德沃德·迈布里奇182周年诞辰,埃德沃德·迈布里奇是运动摄影的开创者,所以谷歌涂鸦以一个运动的摄影作 ...

  2. strings用法小记

    By francis_hao    Feb 14,2017 打印文件中可打印字符,每个序列至少四(可配置)个字符长.主要用于显示非文本文件 概述   选项解释 -a --all - 扫描整个文件,不管 ...

  3. linux bash善用判断式

    1.利用 test 指令的测试功能 $ test -e hello.sh && echo "ok" || echo "no" ok 2.首先,判 ...

  4. BZOJ1202:狡猾的商人(带权并查集)

    1202: [HNOI2005]狡猾的商人 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1202 Description: 刁姹接到一个 ...

  5. mysql修改表中某个字段的默认值

    Mysql中用SQL增加.删除字段,修改字段名.字段类型.注释,调整字段顺序总结   在网站重构中,通常会进行数据结构的修改,所以添加,删除,增加mysql表的字段是难免的,有时为了方便,还会增加修改 ...

  6. ES6学习笔记(二)——数组的扩展

    扩展运算符 ... 将数组转化成用逗号分隔的参数序列 * 扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换. 应用 1. 合并数组 2. 将 ...

  7. java深入解析

    具体内容安排如下: Java Collections Framework概览 对Java Collections Framework,以及Java语言特性做出基本介绍. Java ArrayList源 ...

  8. BZOJ 4514: [Sdoi2016]数字配对

    4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1606  Solved: 608[Submit][Statu ...

  9. hdu 4506 小明系列故事——师兄帮帮忙

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4506 题目大意:找规律,判断k的t次幂前面的系数. #include <iostream> ...

  10. python脚本运行的几种方式

    1.脚本式编程 将如下代码拷贝至 hello.py文件中: print ("Hello, Python!"); 通过以下命令执行该脚本: $ python ./hello.py h ...