链接:登录—专业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);
}