zoukankan      html  css  js  c++  java
  • [ CQOI 2009 ] 中位数图

    (\)

    (Description)


    给出(N)的一个全排列,统计该排列有多少个长度为奇数的连续子序列,中位数是(B)

    • (Nin [0,10^5])(Bin [0,N])

    (\)

    (Solution)


    • 套路做法。将序列中大于(B)的数记为(1),小于记为(-1),那么区间和为(0)当且仅当这一区间内大于(B)和小于(B)的个数一样多,也就是说这个区间的中位数为(B)。另外这一方案的好处是,因为给的是个排列,只要你选定的区间包括(B)且它区间和为(0),这个区间长度一定为奇数。

    • 转化成前缀和相减的形式。每一个位置能产生的贡献是前缀跟他相同且在他前面的位置个数。注意到是排列,所以(B)只有一次,且合法区间必须跨过(B),不妨设(f[0/1][i])代表(B)出现位置的左(/)右,前缀和为(i)的位置个数,这个东西显然扫一遍就可以统计。

    • 显然在(B)同一侧的位置所构成的区间不会产生贡献,所以每一个答案必定由(c[0][i])(c[1][i])中各选一个组合得到,所以最后的答案为(sum_{i=-n}^nc[0][i] imes c[1][i])

    • 注意数列开始时是有一个(0)的,所以要(c[0][0]=1)。处理注意合法闭区间右端点可以是(B)

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 100010
    #define R register
    #define gc getchar
    using namespace std;
     
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
     
    int n,m,ans,cnt[2][N<<1];
     
    int main(){
      n=rd(); m=rd(); cnt[0][n]=1;
      for(R int i=1,now=0,x,sum=n;i<=n;++i){
        x=rd();
        ++cnt[now|=(x==m)][sum+=(x>m)-(x<m)];
      }
      for(R int i=0;i<=(n<<1);++i) ans+=cnt[0][i]*cnt[1][i];
      printf("%d
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    YourSQLDba遭遇.NET Framework Error 6522
    ORACLE NLS_DATE_FORMAT设置
    RHEL下SendMail修改发邮箱地址
    SQL Server如何定位自定义标量函数被那个SQL调用次数最多浅析
    ORACLE归档日志比联机重做日志小很多的情况总结
    ORACLE获取SQL绑定变量值的方法总结
    ORACLE SEQUENCE跳号总结
    ORACLE中seq$表更新频繁的分析
    批量修改所有服务器的dbmail配置
    MySQL 修改账号的IP限制条件
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9673574.html
Copyright © 2011-2022 走看看