ACM学习历程—HDU5701 中位数计数(中位数 && 计数排序)

http://acm.hdu.edu.cn/showproblem.php?pid=5701

这是这次百度之星初赛2B的第六题。之前白山云做过类似的题,省赛完回来,我看了一下大概就有这样的思路:首先枚举每一个数k,计算以这个数为中位数的区间个数。关键是计算中位数的处理方法,将所有大于k的数置为1,小于k的数置为-1,等于k的数置为0。于是区间中位数大于k的区间和就大于0,小于k的小于0,等于k的等于0。而且每个数都不等,所以区间和为0的个数就是中位数为k的个数。

关于计算区间和为0的个数。如果维护前缀和sum的个数。那么维护到i的时候,以i为右区间值的区间必然是sum(i)-sum(j),那么区间和为0就是前面有多少个前缀和为sum(i)。然后区间必须是奇数长度,所以需要对奇偶区间维护前缀和,此外,还需要对sum==0的情况特判。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long

using namespace std;

const int maxN = 8005;
int n, a[maxN], b[maxN];
int cnt[2][maxN<<1];

int cal(int k)
{
    for (int i = 0; i < n; ++i)
    {
        if (a[i] > k) b[i] = 1;
        else if (a[i] < k) b[i] = -1;
        else b[i] = 0;
    }
    int ans = 0, sum = 0;
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < n; ++i)
    {
        sum += b[i];
        ans += cnt[!(i&1)][sum+maxN];
        if (sum == 0 && i%2 == 0) ans++;
        cnt[i&1][sum+maxN]++;
    }
    return ans;
}

void work()
{
    for (int i = 0; i < n; ++i)
    {
        if (i) printf(" ");
        printf("%d", cal(a[i]));
    }
    printf("\n");
}

int main()
{
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    while (scanf("%d", &n) != EOF)
    {
        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
        work();
    }
    return 0;
}
View Code

 

posted on 2016-05-24 15:11  AndyQsmart  阅读(1230)  评论(0编辑  收藏  举报

导航