[TC-FindingFriends]Finding Friends

题目大意:
  给定一个长度为$n(n\le10^5)$的数列$A(A_i\le10^9)$,求最小的$k$满足存在一个长度至少为$m(m\le n)$的子串,对于串中的每一个数$A_i$,都至少存在一个$A_j(i\ne j)$满足$|A_i-A_j|<k$。

思路:
  二分答案$k$,对于每次求出每个元素$A_i$左边离$A_i$最近的满足$|A_i-A_j|<k$的$left[i]=j$,同理求出每个元素$A_j$右边离$A_i$最近的满足$|A_i-A_j|<k$的$right[i]=j$。
  考虑分治,判断区间$[l,r]$是否是满足条件的字串。
  若$r-l+1<m$则显然不满足条件。
  在$[l,r]$中找到一个下标$p$满足$left[p]<l$且$right[p]>r$,则若这样的$p$存在,则包含$p$的区间一定不满足条件,递归处理$[l,p)$和$(p,r]$。若找不到这样的$p$,则该区间满足条件,$k$为合法的答案。
  寻找$p$时,如果不是直接for而是从两端同时往里寻找,设找到的$p$两端的区间长度分别是$a$和$b$,则递归的复杂度是$O(n\log n)$(递推式$T(n)=T(a)+T(b)+\min(a,b)$)。而$left$和$right$的预处理可以用线段树实现,总的时间复杂度是$O(n\log^2 n)$。

  1 #include<vector>
  2 #include<cstdio>
  3 #include<climits>
  4 #include<algorithm>
  5 class FindingFriends {
  6     private:
  7         using int64=long long;
  8         static constexpr int N=1e5+1;
  9         int n,m,lim,arr[N],tmp[N],left[N],right[N];
 10         class SegmentTree {
 11             #define _left <<1
 12             #define _right <<1|1
 13             private:
 14                 int max[N<<2],min[N<<2];
 15                 void push_up(const int &p) {
 16                     max[p]=std::max(max[p _left],max[p _right]);
 17                     min[p]=std::min(min[p _left],min[p _right]);
 18                 }
 19             public:
 20                 void reset() {
 21                     std::fill(&max[0],&max[N<<2],INT_MIN);
 22                     std::fill(&min[0],&min[N<<2],INT_MAX);
 23                 }
 24                 void modify(const int &p,const int &b,const int &e,const int &x,const int &y) {
 25                     if(b==e) {
 26                         max[p]=std::max(max[p],y);
 27                         min[p]=std::min(min[p],y);
 28                         return;
 29                     }
 30                     const int mid=(b+e)>>1;
 31                     if(x<=mid) modify(p _left,b,mid,x,y);
 32                     if(x>mid) modify(p _right,mid+1,e,x,y);
 33                     push_up(p);
 34                 }
 35                 int qmax(const int &p,const int &b,const int &e,const int &l,const int &r) {
 36                     if(b==l&&e==r) return max[p];
 37                     const int mid=(b+e)>>1;
 38                     int ret=INT_MIN;
 39                     if(l<=mid) ret=std::max(ret,qmax(p _left,b,mid,l,std::min(mid,r)));
 40                     if(r>mid) ret=std::max(ret,qmax(p _right,mid+1,e,std::max(mid+1,l),r));
 41                     return ret;
 42                 }
 43                 int qmin(const int &p,const int &b,const int &e,const int &l,const int &r) {
 44                     if(b==l&&e==r) return min[p];
 45                     const int mid=(b+e)>>1;
 46                     int ret=INT_MAX;
 47                     if(l<=mid) ret=std::min(ret,qmin(p _left,b,mid,l,std::min(mid,r)));
 48                     if(r>mid) ret=std::min(ret,qmin(p _right,mid+1,e,std::max(mid+1,l),r));
 49                     return ret;
 50                 }
 51             #undef _left
 52             #undef _right
 53         };
 54         SegmentTree t;
 55         bool check(const int &l,const int &r) {
 56             if(r-l+1<m) return false;
 57             int pos=-1;
 58             for(register int i=0;l+i<=r-i;i++) {
 59                 if(left[l+i]<l&&right[l+i]>r) {
 60                     pos=l+i;
 61                     break;
 62                 }
 63                 if(left[r-i]<l&&right[r-i]>r) {
 64                     pos=r-i;
 65                     break;
 66                 }
 67             }
 68             return pos==-1||check(l,pos-1)||check(pos+1,r);
 69         }
 70         int getlow(const int &x) const {
 71             return std::upper_bound(&tmp[1],&tmp[tmp[0]]+1,x-1)-tmp;
 72         }
 73         int getup(const int &x) const {
 74             return std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,x+1)-1-tmp;
 75         }
 76         bool check(const int &k) {
 77             t.reset();
 78             for(register int i=1;i<=n;i++) {
 79                 left[i]=t.qmax(1,1,tmp[0],std::max(getlow(tmp[arr[i]]-k),1),std::min(getup(tmp[arr[i]]+k),tmp[0]));
 80                 t.modify(1,1,tmp[0],arr[i],i);
 81             }
 82             t.reset();
 83             for(register int i=n;i>=1;i--) {
 84                 right[i]=t.qmin(1,1,tmp[0],std::max(getlow(tmp[arr[i]]-k),1),std::min(getup(tmp[arr[i]]+k),tmp[0]));
 85                 t.modify(1,1,tmp[0],arr[i],i);
 86             }
 87             return check(1,n);
 88         }
 89     public:
 90         int shortestDistance(const int &nn,const std::vector<int> &init,const int &a,const int &b,const int &c,const int &d,const int &mm) {
 91             n=nn,m=mm;
 92             for(register unsigned i=0;i<init.size();i++) arr[i+1]=init[i];
 93             for(register int i=init.size();i<n;i++) {
 94                 arr[i+1]=(((int64)arr[i]*a%d+(int64)b*i%d)%d+c)%d;
 95             }
 96             lim=*std::max_element(&arr[1],&arr[n]+1);
 97             std::copy(&arr[1],&arr[n]+1,&tmp[1]);
 98             std::sort(&tmp[1],&tmp[n]+1);
 99             tmp[0]=std::unique(&tmp[1],&tmp[n]+1)-&tmp[1];
100             for(register int i=1;i<=n;i++) {
101                 arr[i]=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,arr[i])-tmp;
102             }
103             int l=0,r=lim;
104             while(l<=r) {
105                 const int mid=(l+r)/2;
106                 if(check(mid)) {
107                     r=mid-1;
108                 } else {
109                     l=mid+1;
110                 }
111             }
112             return r+1;
113         }
114 };

 

posted @ 2018-05-21 14:40  skylee03  阅读(290)  评论(0编辑  收藏  举报