Codeforces Round #171 (Div. 2) C. Ladder(二分)
题目大意
给你一组数 a(1),a(2),a(3),...,a(n) (n<=10^5),以及 m(m<=10^5) 个 query,每个 query 的格式为 l(i) r(i),问数组中从 l(i) 到 r(i) 中的数是否是一个 lander(梯子?)
一个 lander 的定义是:对于一列数 b(1),b(2),b(3),...,b(k),存在一个数 x(1<=x<=k),使得:b(1)<=b(2)<=b(3)<=...<=b(x)<=b(x+1)<=...<=b(k)
做法分析
定义两个数组:inc[] 和 dec[]
初始化 inc[0]=dec[0]=0
对于 inc 数组,如果 a(i)>=a(i-1) 那么 inc[i]=inc[i-1]+1 否则 inc[i]=inc[i-1]-1
对于 dec 数组,如果 a(i)<=a(i-1) 那么 dec[i]=dec[i-1]+1 否则 dec[i]=dec[i-1]-1
这两个数组有这样的性质:
如果 a(i)<=a(i+1)<=...<=a(j) 那么就有 inc[j]-inc[i]==j-i
如果 a(i)>=a(i+1)>=...>=a(j) 那么就有 dec[j]-dec[i]==j-i
知道了这两个数组的性质,就可以利用二分来解决此题了,对每一个 query 具体做法就是
先找到最大的 k(k<=r(i)) 使得 a(l(i))<=a(l(i)+1)<=...<=a(k) (这里可以用二分查找哦!!)
再判断 dec[r(i)]-dec[k] 是否等于 r(i)-k,如果是,那么这一段是一个 lander,否则不是
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstring> 2 #include <cstdio> 3 4 using namespace std; 5 6 const int N=100006; 7 8 int inc[N], dec[N]; 9 int n, m, a[N]; 10 11 int main() 12 { 13 scanf("%d%d", &n, &m); 14 for(int i=1; i<=n; i++) scanf("%d",&a[i]); 15 inc[0]=dec[0]=0; 16 inc[1]=dec[1]=1; 17 for(int i=2; i<=n; i++) 18 { 19 dec[i]=dec[i-1]; 20 inc[i]=inc[i-1]; 21 if(a[i]>a[i-1]) dec[i]--; 22 else dec[i]++; 23 if(a[i]<a[i-1]) inc[i]--; 24 else inc[i]++; 25 } 26 27 for(int i=0; i<m; i++) 28 { 29 int st, en; 30 scanf("%d%d", &st, &en); 31 int L=st, R=en; 32 while(L<R) 33 { 34 int mid=(L+R)>>1; 35 if(inc[mid]-inc[st]<mid-st) R=mid; 36 else L=mid+1; 37 } 38 if(inc[L]-inc[st]<L-st) L--; 39 if(dec[en]-dec[L]!=en-L) printf("No\n"); 40 else printf("Yes\n"); 41 } 42 return 0; 43 }
AC通道
Codeforces Round #171 (Div. 2) C. Ladder