[單調棧 線段樹] Codeforces 407E Round #239 (Div. 1) E. k-d-sequence

首先肯定是一段模 d 相同的數
然後枚舉左端點 那麼右端點應該滿足條件 數字不重複出現且 maxvl,rminvl,rrl+k ,這個最大最小值是除過 d
也就是

maxvl,rminvl,rrkl

左端點邊挪邊用單調棧維護最大最小值 入棧出棧就線段樹上區間修改一下
然後查詢最右邊的滿足條件的
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<map>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=200005;

int n,K,d;
int a[N];

namespace Work{
  int ans1=1,ans2=1;
  inline void Solve(){
    int ans=0;
    for (int i=1,j;i<=n;i=j+1){
      j=i;
      while (j+1<=n && a[i]==a[j+1]) j++;
      if (j-i>ans2-ans1 || (j-i==ans2-ans1 && i<ans1))
      ans1=i,ans2=j;
    }
    printf("%d %d\n",ans1,ans2);
  }
}

int T[N<<2],F[N<<2];
inline void mark(int x,int a){
  T[x]+=a; F[x]+=a;
}
inline void push(int x){
  if (F[x]) mark(x<<1,F[x]),mark(x<<1|1,F[x]),F[x]=0;
}
inline void Build(int x,int l,int r){
  if (l==r) return void(T[x]=-l);
  int mid=(l+r)>>1; Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
  T[x]=min(T[x<<1],T[x<<1|1]);
}
inline void Add(int x,int l,int r,int ql,int qr,int a){
  if (ql<=l && r<=qr){ mark(x,a); return; }
  push(x);
  int mid=(l+r)>>1;
  if (ql<=mid) Add(x<<1,l,mid,ql,qr,a);
  if (qr>mid) Add(x<<1|1,mid+1,r,ql,qr,a);
  T[x]=min(T[x<<1],T[x<<1|1]);
}
int Ret=0;
inline void query(int x,int l,int r,int K){
  if (l==r) return void(Ret=l);
  push(x); int mid=(l+r)>>1;
  if (T[x<<1|1]<=K) query(x<<1|1,mid+1,r,K);
  else query(x<<1,l,mid,K);
}
inline void Query(int x,int l,int r,int ql,int qr,int lim){
  if (Ret) return;
  if (ql<=l && r<=qr){
    if (T[x]<=lim) query(x,l,r,lim);
    return;
  }
  push(x);
  int mid=(l+r)>>1;
  if (qr>mid) Query(x<<1|1,mid+1,r,ql,qr,lim);
  if (ql<=mid) Query(x<<1,l,mid,ql,qr,lim);
}

map<int,int> nxt;
int last[N];
int sta1[N],pnt1; //max
int sta2[N],pnt2; //min

int ans1=1,ans2=1;

inline void Solve(int l,int r){
  if (l==r) return;
  for (int i=l;i<=r;i++) a[i]=(a[i]+1e9)/d+1;
  int R=r+1;
  pnt1=pnt2=0; sta1[0]=sta2[0]=r+1;
  for (int i=r;i>=l;i--){
    if (nxt.count(a[i])) R=min(R,nxt[a[i]]);

    while (pnt1 && a[i]>a[sta1[pnt1]]){
      Add(1,1,n,sta1[pnt1],sta1[pnt1-1]-1,-a[sta1[pnt1]]);
      pnt1--;
    }
    sta1[++pnt1]=i;
    Add(1,1,n,sta1[pnt1],sta1[pnt1-1]-1,a[i]);

    while (pnt2 && a[i]<a[sta2[pnt2]]){
      Add(1,1,n,sta2[pnt2],sta2[pnt2-1]-1,a[sta2[pnt2]]);
      pnt2--;
    }
    sta2[++pnt2]=i;
    Add(1,1,n,sta2[pnt2],sta2[pnt2-1]-1,-a[i]);

    Ret=0; Query(1,1,n,i,R-1,K-i);
    if (Ret-i>ans2-ans1 || (Ret-i==ans2-ans1 && i<ans1))
      ans1=i,ans2=Ret;

    nxt[a[i]]=i;
  }
  nxt.clear();
}

int main(){
  freopen("bug.in","r",stdin);
  freopen("bug.out","w",stdout);
  read(n);read(K);read(d); for (int i=1;i<=n;i++) read(a[i]);
  if (d==0){
    Work::Solve();
    return 0;
  }
  Build(1,1,n);
  for (int i=1,j;i<=n;i=j+1){
    j=i; while (j+1<=n && (a[i]%d+d)%d==(a[j+1]%d+d)%d) j++;
    Solve(i,j);
  }
  printf("%d %d\n",ans1,ans2);
  return 0;
}
發佈了975 篇原創文章 · 獲贊 67 · 訪問量 55萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章