[CQOI2009]中位数图(牛客)

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述

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

输入描述:

第一行为两个正整数n和b ,第二行为1~n 的排列。

输出描述:

输出一个整数,即中位数为b的连续子序列个数。

示例1

输入

7 4
5 7 2 4 3 1 6

输出

4


思路:

题意即找出包含中位数的奇数连续子序列。

在子序列中只有三种情况:大于或小于或等于中位数,所以可以将将数组中大于中位数的数设置为1,小于的设置为-1

在题目中,可分为2种情况进行讨论:

1.仅靠一边就可以实现题目所需要的连续子序列,此时仅需要一个变量sum计算出后缀和就可以完成所有判断

2.需要靠两边各自一部分实现题目所需要的连续子序列,此时则需要num数组来记录当前sum的次数。这样在遍历右边每项的时候,可以求出当前右边项的后缀和sum的值,当sum!=0时意味着需要左边的一部分来完成。

例如,当前的右边其中一个sum=-1,意味着此时我需要一个左边sum=1所代表的部分就可以共同构建出题目所要的答案,所以直接ans+=左边记录着的sum左=1的个数(即num[1])(+=是因为有多少个加多少,如num[1]=1就是有1个sum=1,num[1]=2就是有2个sum=1,其中这两个是有包含含义的,即这两个num都可以对右边的起作用,所以ans可以直接加)

另外,对于num[]中的正负号因为得到右边的其中一个后缀和时,要与左边对应后缀和关联起来需要一个负号,如当前右边的sum=-1,此时需要关联起左边的num[1],则把自己的sum变成相反数即可,因为数组没有负号,所以sum1与-sum2都同时加上一个数,为了方便计算,同时加上n

#include<iostream>
#define N 100010
using namespace std;

int a[N], sum, num[N], ans = 1;///num记录着每一个后缀和出现的次数

int main(){
    int n, b, k;cin >> n >> b;
    for( int i = 1; i <= n; i ++ ){
        cin >> a[i];
        ///对当前a[i]的值与中位数比较并转化成1 -1 0
        if( a[i] < b )a[i] = -1;
        else if( a[i] > b )a[i] = 1;
        else a[i] = 0,k = i;
    }
    for( int i = k-1; i >= 1; i -- ){///先对一边进行操作
        sum += a[i];///统计当前能不能满足答案
        num[n+sum]++;///同时记录当前位置的sum个数
        if( !sum )ans++;
    }
    sum = 0;
    for( int i = k+1; i <= n; i ++ ){
        sum += a[i];
        ans += num[n-sum];
        ///需要用减是因为左边多余的项需要右边一个与其相反的数,同时还要减去才能和左边的相等
        if( !sum )ans++;
    }
    printf("%d",ans);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值