zoukankan      html  css  js  c++  java
  • 牛客国庆训练,CCPC Camp DAY1 J 倍增,括号匹配

    https://www.nowcoder.com/acm/contest/201#question

    题意:中文不翻译了

    解法的个人理解:

      对于一个合法的区间$[L,R]$

      1.显然其左括号的匹配位置都小于等于$R$,其右括号的匹配位置都大于等于$L$,

      2.左括号和右括号数量相同

      3.区间的长度为偶数

      后面两点是必要的,但是不够充分

      第一点是最关键的,我们可以考虑转化

      如果将整个序列左括号所匹配的位置记录下来作为数列$a_i$,同理右括号记为$b_i$原本的询问就等于是询问一个区间最大值和区间最小值了

      即$a_i$的最大值小于$R$,$b_i$的最小值小于$L$,至于具体怎么查,用st表,线段树,树状数组都行

      而实际上,在满足2,3条件之后,最大值和最小值只用计算其中一个即可

      例如满足了左括号的匹配位置都小于$R$,那么区间内的左括号都已经找到归属了,换句话说只要左括号和右括号数目相等,则必然合法

    代码如下:

    #include <bits/stdc++.h>
    #define rep(ii,a,b) for(register int ii=a;ii<=b;++ii)
    #define per(ii,a,b) for(register int ii=b;ii>=a;--ii)
    using namespace std;
    const int maxn=2e6+10,maxm=2e6+10;
    int casn,n,m,k,q,a[maxn],stk[maxn];
    int l[maxn],sum[maxn],st[maxn][22],top,ll,rr;
    inline int rmax(int ll,int rr){
      int len=0;
      while(ll+(1<<len)-1<=rr) len++;
      len--;
      return max(st[ll][len],st[rr-(1<<len)+1][len]);
    }
    int main() {
    	scanf("%d%d%d",&n,&m,&q);
    	rep(i,1,n) scanf("%d",&a[i]);
    	rep(i,1,n)
    		if(a[i]%2) sum[i]=sum[i-1]-1;
    		else sum[i]=sum[i-1]+1;
    	per(i,1,n)
    		if(a[i]%2)stk[++top]=i;
    		else{
    			if(top&&a[i]/2==a[stk[top]]/2){
            l[i]=stk[top--];
    			}else {
            l[i]=maxn+10;
            top=0;
    			}
    		}
    	rep(i,1,n) st[i][0]=l[i];
    	rep(i,1,21) rep(j,1,n)
          st[j][i]=max(st[j][i-1],st[min(j+(1<<(i-1)),n)][i-1]);
      while(q--){
        scanf("%d%d",&ll,&rr);
        if((rr-ll+1)%2==0&&sum[rr]==sum[ll-1]&&rmax(ll,rr)<=rr)
          puts("Yes");
        else
          puts("No");
       }
      return 0;
    }
    

      

  • 相关阅读:
    Web应用网络模型
    Http协议
    Array数组标准库
    Array数组基础
    javascript--Object
    javascript--Function
    letCode-3
    面试前的准备
    面试常见问题
    面试经验总结
  • 原文地址:https://www.cnblogs.com/nervendnig/p/9736184.html
Copyright © 2011-2022 走看看