BZOJ4527 : K-D-Sequence

先把所有数减去最小值,防止负数出现问题。

$d=0$,直接$O(n)$扫过去即可。

$d\neq 0$,首先通过双指针求出每个数作为右端点时往左可以延伸到哪里,中间任意两个数差值都是$d$的倍数且不重复。

然后从左往右枚举右端点$i$,那么左端点$j$需要满足:

$\lfloor\frac{\max(a[j]..a[i])}{d}\rfloor-\lfloor\frac{\min(a[j]..a[i])}{d}\rfloor+j\leq k+i$

用线段树+单调栈进行$\max$和$\min$的更新,并维护区间内这个式子的最小值,然后在线段树上二分即可。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
const int N=200010,M=524300;
int n,k,d,i,j,mi=~0U>>1,a[N],b[N],c[N],l[N],ap[N],cnt,q0[N],t0,q1[N],t1,t,L=1,R;
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>=‘0‘)&&(c<=‘9‘))||(c==‘-‘)));
  if(c!=‘-‘)a=c-‘0‘;else f=1;
  while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;
  if(f)a=-a;
}
inline void uans(int l,int r){if(r-l>R-L||r-l==R-L&&l<L)L=l,R=r;}
inline int lower(int x){
  int l=1,r=n,mid,t;
  while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
  return t;
}
inline int abs(int x){return x>0?x:-x;}
int ma[M],mb[M],mc[M],mac[M],mbc[M],mabc[M],ta[M],tb[M];
inline int min(int a,int b){return a<b?a:b;}
inline void taga(int x,int p){ma[x]=ta[x]=p;mac[x]=mc[x]+p;mabc[x]=mbc[x]+p;}
inline void tagb(int x,int p){mb[x]=tb[x]=p;mbc[x]=mc[x]+p;mabc[x]=mac[x]+p;}
inline void pb(int x){
  if(~ta[x])taga(x<<1,ta[x]),taga(x<<1|1,ta[x]),ta[x]=-1;
  if(tb[x]<=0)tagb(x<<1,tb[x]),tagb(x<<1|1,tb[x]),tb[x]=1;
}
inline void up(int x){
  ma[x]=min(ma[x<<1],ma[x<<1|1]);
  mb[x]=min(mb[x<<1],mb[x<<1|1]);
  mac[x]=min(mac[x<<1],mac[x<<1|1]);
  mbc[x]=min(mbc[x<<1],mbc[x<<1|1]);
  mabc[x]=min(mabc[x<<1],mabc[x<<1|1]);
}
void build(int x,int a,int b){
  mc[x]=mac[x]=mbc[x]=mabc[x]=a;
  ta[x]=-1,tb[x]=1;
  if(a==b)return;
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void changea(int x,int a,int b,int c,int d,int p){
  if(c<=a&&b<=d){taga(x,p);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)changea(x<<1,a,mid,c,d,p);
  if(d>mid)changea(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
void changeb(int x,int a,int b,int c,int d,int p){
  if(c<=a&&b<=d){tagb(x,p);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)changeb(x<<1,a,mid,c,d,p);
  if(d>mid)changeb(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
void dfs(int x,int a,int b,int p){
  if(a==b){t=a;return;}
  pb(x);
  int mid=(a+b)>>1;
  if(mabc[x<<1]<=p)dfs(x<<1,a,mid,p);else dfs(x<<1|1,mid+1,b,p);
  up(x);
}
void ask(int x,int a,int b,int c,int d,int p){
  if(t)return;
  if(c<=a&&b<=d){
    if(mabc[x]<=p)dfs(x,a,b,p);
    return;
  }
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)ask(x<<1,a,mid,c,d,p);
  if(d>mid)ask(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
int main(){
  read(n),read(k),read(d);
  for(i=1;i<=n;i++){
    read(a[i]);
    if(a[i]<mi)mi=a[i];
  }
  if(!d){
    for(i=j=1;i<=n;i++){
      if(a[i]!=a[j])j=i;
      uans(j,i);
    }
    uans(j,n);
    return printf("%d %d",L,R),0;
  }
  for(i=1;i<=n;i++)a[i]-=mi,b[i]=a[i];
  for(std::sort(b+1,b+n+1),i=1;i<=n;i++)c[i]=lower(a[i]);
  for(i=j=1;i<=n;i++){
    if(!ap[c[i]])cnt++;ap[c[i]]++;
    while(cnt<i-j+1){
      ap[c[j]]--;if(!ap[c[j]])cnt--;
      j++;
    }
    l[i]=j;
  }
  for(i=j=1;i<=n;i++){
    if(abs(a[i]-a[i-1])%d)j=i;
    if(l[i]<j)l[i]=j;
  }
  build(1,1,n);
  for(i=1;i<=n;i++){
    while(t0&&a[q0[t0]]<a[i])t0--;
    changea(1,1,n,q0[t0]+1,i,a[i]/d);
    q0[++t0]=i;
    while(t1&&a[q1[t1]]>a[i])t1--;
    changeb(1,1,n,q1[t1]+1,i,-a[i]/d);
    q1[++t1]=i;
    t=0,ask(1,1,n,l[i],i,k+i);
    uans(t,i);
  }
  return printf("%d %d",L,R),0;
}

  

时间: 2024-10-11 09:44:16

BZOJ4527 : K-D-Sequence的相关文章

leetcode笔记:Permutation Sequence

一.题目描述 题目的意思是,假设有{1,2,3,4,-,n},对其中的元素进行排列,总共有n!种组合,将它们从小到大排序,问其中第k个组合的形式是怎样的? 二.题目分析 方法一:可以一个一个的按次序暴力求解.具体实现可参照题目:Next Permutation.这里并没有实现,主要研究的是方法二的Cantor expansion算法. 方法二:数学解法:Cantor expansion Cantor expansion算法的思想是,在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如

【dfs】Sequence Decoding

Sequence Decoding 题目描述 The amino acids in proteins are classified into two types of elements, hydrophobic (nonpolar) and hydrophilic (polar). Hydrophobic and hydrophilic are denoted by H and P respectively. A protein is represented by a sequence of H

python随机数

前提:需要导入random模块 >>>import random 1.random.random random.random()用于生成一个0到1的随机符小数: 0 <= n < 1.0 >>> random.random()        # Random float x, 2.random.uniform random.uniform的函数原型为:random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是

python随机数的产生

导入 random模块  >>> import random 1.  random.random random.random()用于生成一个0到1的随机浮点数: 0 <= n < 1.0 >>> random.random()        # Random float x, 2    random.uniform random.uniform的函数原型为:random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,

HackerRank - Substring Diff

Really interesting problem. Naive solution would be O(n^3). But please note the pattern here: (i, j, k) -> (i + 1, j + 1, k) -> (i + 2, j + 2, k)... this sequence shares the same pattern, so now the problem can be deducted to "what is the longe

CNN-tracking-文章导读

1.MDnet:learning multi-domain convolution neural networks for visual tracking MDnet是vot2015的冠军paper,由韩国Postech的Bohyung Han发表,测试了代码,在多个benchMark上的测试结果都比较好,但是速度比较慢,1fps,下面就开始介绍这篇paper的整体思路. 1.1 文章特点 a) shared layer 为offline train, unshared layer的parame

斐波那契数列计算时间复杂度之彻底分析

#include<stdio.h> #include<time.h> 递归法: 优点:形式简洁,便于人理解 缺点:虽说递归法以空间换时间,但一旦n变大,它的速度的确比非递归法慢得多,例如对n=40,测试递归法所用时间为8~9s;而非递归法只需要远不到1s. 原因是,递归过程中,系统建立堆栈来保存上一层状态信息, 和退栈获取还原系统状态都要有开销的.系统做的事情不少, 所以效率要低. 例如,f(5)的话,实际上会调用这个函数15次,有15个临时栈区,试想f(100)有多吓人...一般

剑指Offer--二叉搜索数的后序遍历序列

题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 思路 刚开始没有什么思路,但是通过画图分析就知道数组的最后一个是二叉树的根节点,它将数组的剩余部分分成了两部分,前一部分小于根节点的值,有一部分大于根界定啊的值,然后递归: import java.util.ArrayList; public class Solution { //画图分析可知最后一个一定是根节点,根节点将数组的其余部分分成了两部分,这

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

题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 题目地址 https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

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

Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力) 题目描述 如果一个数组1.至少三个元素2.两两之间差值相同,那么这个数组就是算术序列 比如下面的数组都是算术序列: 1, 3, 5, 7, 9 7, 7, 7, 7 3, -1, -5, -9 但是这一个就不是: 1, 1, 2, 5, 7 求给定数组,能有多少个算术序列 测试样例 Input: [1, 2, 3, 4] Output: 3 有三个算术序列切片: [1,2,3], [2,3,4], [1