• 【CQOI2008】中位数


    题不难,但是思路有意思,这个是我自己想出来的OvO

    原题:

    给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。

    n<=100000

    刚看这道题的时候看n滋瓷nlogn的复杂度,又是维护区间关系的,觉得应该要用数据结构

    然后开始想数据结构,思考中位数的特殊性,题目中限定子序列的长度为奇数,b是一个长度为奇数的序列的中位数就说明在这个序列中比b大的数和比b小的数相等

    子序列中的东西有多少个,这个可以用前缀搞

    然后发现让前缀中比b大的数和比b小的数做差,如果两个前缀和相等的话,说明这个这两个前缀和中间的区间比b大的数和比b小的数相等

    证明的话可以设前缀和a,b比b大和比b小的数分别为(x1,y1),(x2,y2),差的前缀和为y1-x1,y2-x2,这两个前缀和中间比b大的数有x2-x1,比b小的有y2-y1,如果两个差的前缀和相等,则y1-x2=y2-x2,移项就可以得到x2-x1=y2-y1,满足子序列中比b大的数个数和比b小的数个数相等,即这个子序列的中位数就是b

    子序列长度为奇数的条件很好满足,因为我们是两个前缀和相减,所以可以把前缀和分成两份,分别是右顶点为奇数和偶数的前缀和,让两个奇偶性不同的前缀和相减就可以了

    具体怎么搞的话,就是搞一个cnt记录直到第i个数比b大的数个数减比b小的数个数是多少,每次看和i奇偶性相反,值为cnt的前缀和个数有多少个,加到答案上即可

    不用记录前缀和,直接搞一个计数,s[i][j]表示值为i,奇偶性为j的前缀和有多少个就可以辣

    两个前缀和的值相等但是这两个前缀和中间的子序列中没有出现b的情况是不存在的,因为子序列一定是奇数,没有b出现的话,一个数要么比b大,要么比b小,奇数个数没法平分

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 int read(){int z=0,mark=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mark;
    12 }
    13 int n,m,s[210000][2];
    14 int main(){//freopen("ddd.in","r",stdin);
    15     cin>>n>>m;
    16     int u,cnt=0,ans=0;
    17     s[n][0]=1;
    18     for(int i=1;i<=n;++i){
    19         u=read();
    20         if(u!=m)  cnt+=u>m?1:-1;
    21         ans+=s[cnt+n][i&1^1];//先与1判断奇偶,然后再^1取到和i奇偶性相反的奇偶性
    22         s[cnt+n][i&1]++;
    23     }
    24     cout<<ans<<endl;
    25     return 0;
    26 }
    View Code
  • 相关阅读:
    编译原理基础知识---文法和语言(一)
    编译原理简单知识总结(一)---编译程序和解释程序
    python网络编程
    博客声明
    v4l2编程
    Linux中的虚拟文件系统
    linux 内核文件中Makefile、kconfig、.config的关系(SDK结构)
    shell编程---find命令
    springcloud、springboot 版本号解析
    List<Map<String, Object>> 与 json 互转
  • 原文地址:https://www.cnblogs.com/JSL2018/p/6406313.html
Copyright © 2020-2023  润新知