[CQOI2009]中位数图 详细题解

题目链接: https://ac.nowcoder.com/acm/problem/19913
题目描述:
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
题解:
因为中位数是位于一个序列中最中间的数字了,所以这个序列左边的数的个数是要等于它右边的个数的,所以我们可以把序列给替换成1和-1的序列,大于这个数的换成1,小于这个数的换程-1,这样的话我们可以分为三种情况来统计这个序列的个数
1.0到pos-1
2.pos+1到n-1
3.0到pos到n-1
(因为序列必须是连续的)第一种情况好统计,也就是说我们找一个sum来记录从pos-1位置往前走,每走一步加一下(已经改过的a[i]),当sum=0的时候就意味着大于m的数和小于m的数相等,故sum++;
当然第二种情况也可以由上面的那种方法进行统计。
但是最后一种情况怎么统计呢,我们可以在统计第一种情况的时候顺便统计cnt[maxn+sum]++,这个代表着什么呢,也就是说这个后缀和为maxn+sum的总序列数到底有多少个,故,我们在进行第三种情况的统计时,当maxn-sum,也就是说,假设走到某个位置,此时从pos到这个位置sum的相反数的序列情况有几种,(这个相反数的序列总数在第一种情况已经统计过了),所以我们在统计第二种情况的时候顺便可以统计第三种情况了,ans+=cnt[maxn-sum],为什么时-sum,因为我们要大于m的数正好等于小于m的数,才能保证m是中位数。

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
const int maxn = 1e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 1000007;
using namespace std;
int a[maxn];
int cnt[maxn*2];
int main()
{
    int n,m,pos;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(a[i]>m) a[i]=1;
        else if(a[i]<m) a[i]=-1;
        else a[i]=0,pos=i;
    }
    int sum=0,ans=0;
    for(int i=pos-1;i>=0;i--){
        sum+=a[i];
        if(sum==0) ans++;
        cnt[maxn+sum]++;
    }
    sum=0;
    for(int i=pos+1;i<n;i++){
        sum+=a[i];
        if(sum==0) ans++;
        ans+=cnt[maxn-sum];
    }
    cout<<ans+1<<endl;
    return  0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值