[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 };