CF407E k-d-sequence
时间:2021-07-14
本文章向大家介绍CF407E k-d-sequence,主要包括CF407E k-d-sequence使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、题目
二、解法
注意题目问的是区间啊,我以为是子序列就一直做不起。
\(d=0\) 特判,然后我们只考虑连续的\(\bmod d\) 余数相同的一段,现在翻译一下题目条件:
- \([l,r]\) 中不出现相同的数。
- \(\frac{\max[l:r]-\min[l:r]}{d}\leq k+r-l\),移个项:\(\max[l:r]-\min[l:r]+l\cdot d\leq (k+r)\cdot d\)
主要问题是第二个限制,我们把左边的叫做区间 \([l,r]\) 的权值。那么我们固定右端点,维护出每个左端点的权值,想到用线段树维护权值,但是 \(\max,\min\) 有点不好搞。根据套路可以维护一个单调栈,栈内的每个元素都有一个管辖区间,代表如果 \(l\) 取值再这个区间内,那么最值就是这个元素。我们在弹出栈顶时在线段树上区间修改这个栈顶管辖区间的贡献即可。
然后在线段树上二分查权值不超过某个值得最小左端点即可。最后说下怎么做第一个限制,你会发现满足第一个限制的 \(l\) 是单调的,可以 \(\tt two-pointers\),发现不行了直接永久删除即可(打极大值标记)
时间复杂度 \(O(n\log n)\)
三、总结
区间问题考虑左端点用来干什么?右端点用来干什么?怎么维护?
最大最小值可以单调栈来辅助线段树维护,这个套路以前优化 \(dp\) 时也见过。
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
const int M = 200005;
#define int long long
const int inf = 1e18;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,d,ans,pl,pr,a[M],b[M];
int s1[M],s2[M],mi[4*M],tag[4*M];
void down(int i)
{
if(!tag[i]) return ;
tag[i<<1]+=tag[i];
tag[i<<1|1]+=tag[i];
mi[i<<1]+=tag[i];
mi[i<<1|1]+=tag[i];
tag[i]=0;
}
void ins(int i,int l,int r,int L,int R,int v)
{
if(L>r || l>R) return ;
if(L<=l && r<=R)
{
mi[i]+=v,tag[i]+=v;
return ;
}
int mid=(l+r)>>1;down(i);
ins(i<<1,l,mid,L,R,v);
ins(i<<1|1,mid+1,r,L,R,v);
mi[i]=min(mi[i<<1],mi[i<<1|1]);
}
int find(int i,int l,int r,int v)
{
if(mi[i]>v) return 0;
if(l==r) return l;
int mid=(l+r)>>1;down(i);
if(mi[i<<1]<=v) return find(i<<1,l,mid,v);
return find(i<<1|1,mid+1,r,v);
}
void work(int x)
{
for(int i=1;i<=4*m;i++)
mi[i]=tag[i]=0;
int t1=0,t2=0,L=0;
ins(1,1,m,1,m,inf);
map<int,int> cnt;
for(int i=1;i<=m;i++)
{
ins(1,1,m,i,i,-inf+i*d);//light it up
//maintain MAX
while(t1 && b[s1[t1]]<=b[i])
{
ins(1,1,m,s1[t1-1]+1,s1[t1],-b[s1[t1]]);
t1--;
}
ins(1,1,m,s1[t1]+1,i,b[i]);
s1[++t1]=i;
//maintain MIN
while(t2 && b[s2[t2]]>=b[i])
{
ins(1,1,m,s2[t2-1]+1,s2[t2],b[s2[t2]]);
t2--;
}
ins(1,1,m,s2[t2]+1,i,-b[i]);
s2[++t2]=i;
//a[l:r] can't have same value
cnt[b[i]]++;
while(cnt[b[i]]>1)
{
L++;
ins(1,1,m,L,L,inf);//turn it down
cnt[b[L]]--;
}
//updata the answer
int t=find(1,1,m,(i+k)*d);//all d times
if(t && ans<i-t+1)
ans=i-t+1,pl=t+x-1,pr=i+x-1;
}
}
signed main()
{
n=read();k=read();d=read();
for(int i=1;i<=n;i++) a[i]=read();
if(d==0)
{
for(int i=1,j=i;i<=n;)
{
while(j<=n && a[i]==a[j]) j++;
if(j-i>ans)
ans=j-i,pl=i,pr=j-1;
i=j;
}
printf("%lld %lld\n",pl,pr);
return 0;
}
for(int i=1,j=i;i<=n;)
{
m=0;
while(j<=n && (a[i]%d+d)%d==(a[j]%d+d)%d)
b[++m]=a[j],j++;
work(i);i=j;
}
printf("%lld %lld\n",pl,pr);
}
原文地址:https://www.cnblogs.com/C202044zxy/p/15010229.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- kotlin gson反序列化默认值失效深入讲解
- Android使用Volley实现上传文件功能
- 工作中使用jasmine遇到的一个html element和Component绑定属性失去同步的问题
- Android使用Volley框架定制PostUploadRequest上传文件
- Android实现横向滑动卡片效果
- 在jasmine beforeEach里修改UI元素的一个side effect
- Android实现头像上传功能
- 关于jasmine里debugElement.query和fixture.detectChanges的依赖关系
- 使用python批量转换文件编码为UTF-8的实现
- rxjs operator学习笔记
- python实现将两个文件夹合并至另一个文件夹(制作数据集)
- rxjs里使用from operator从一个generator里生成Observable
- 使用asyncScheduler进行Observable的延迟subscribe
- 解决flask接口返回的内容中文乱码的问题
- Android自定义控件实现带数值和动画的圆形进度条