zoukankan      html  css  js  c++  java
  • 【题解】[CQOI2009] 中位数

    题目信息

    题目来源:CCF 重庆省选 2009;

    在线评测地址:Luogu#1627

    运行限制:时间不超过 (1.00 extrm{s}),空间不超过 (128 extrm{MiB})

    题目描述

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

    输入格式

    第一行为两个正整数 (n)(b),第二行为 (1,2,cdots,n) 的排列。

    输出格式

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

    数据规模与约定

    • 对于 (30\%) 的数据中,满足 (nle 100)
    • 对于 (60\%) 的数据中,满足 (nle 1000)
    • 对于 (100\%) 的数据中,满足 (nle 10^5)(1le ble n)

    分析

    插一句题外话,这道题与 CSP-S2019 D1T2 有异曲同工之妙。

    (30 exttt{pts})

    枚举所有连续子序列,暴力排序找中位数。

    复杂度:(mathcal{O}(n^3log n))

    (60 exttt{pts})

    我们观察一下这种子序列的条件:

    • 连续且包含 (b) 这个元素;
    • (b) 是这个子序列的中位数。

    根据排序的定义,可以将后面这个条件转换成「若连续子序列的长度为 (t),则 (b) 是第 (leftlceildfrac{t}{2} ight ceil) 大,也就是说比 (b) 大的数与比 (b) 小的数数量相同」。

    这样,我们只需要遍历左端点在 (b) 及其左边,右端点在 (b) 及其右边的连续子序列,用前缀和处理出比 (b) 大和比 (b) 小的数的数量。

    复杂度:(mathcal{O}(n^2))

    (100 exttt{pts})

    想到了 (60) 分做法,(100) 分也简单了。

    预处理出比 (b) 大的数的数量减去比 (b) 小的数的数量的值。如果有两个前缀和和相等,就有一个这样的数列。

    易证这个值一定在 ([-n,n]) 的范围内,用一个数组 (cnt_i) 记录下值为 (i) 的前缀和的数量。

    处理 (b) 左边时,将左边的前缀和统计进去。处理右边时,计算前缀和 (S_i) 并让 (ansleftarrow ans+cnt_{S_i})

    这样就能在 (mathcal{O}(n)) 的时间内完成了。

    注意事项

    如果你统计左边的前缀和时从前往后统计的,计算右边的答案时 (S_i) 就得是正的,否则 (S_i) 就得是负的,同时右边的前缀和就得从 (b) 开始统计。

    Code

    #include <cstdio>
    using namespace std;
    
    constexpr int max_n = 100000;
    int a[max_n], cnt[max_n*2+1]; // 原数组+数量统计
    
    int main()
    {
    	int n, k, ptr, pos = -1, tmp, ans = 0;
    
    	scanf("%d%d", &n, &k);
    	for (int i = 0; i < n; i++) // 读入
    	{
    		scanf("%d", a + i);
    
    		if (a[i] == k) // 记录位置
    			pos = i;
    	}
    	
    	cnt[max_n]++, tmp = 0;
    	for (int i = pos - 1; i >= 0; i--) // 统计左边的前缀和
    	{
    		tmp += (a[i] > k)? 1:-1; // 计算
    		cnt[tmp+max_n]++; // 统计上
    	}
    
    	tmp = 0, ans += cnt[max_n];
    	for (int i = pos + 1; i < n; i++) // 计算答案
    	{
    		tmp += (a[i] > k)? -1:1;
    		ans += cnt[max_n-tmp]; // 我的写法是减去
    	}
    
    	printf("%d
    ", ans);
    
    	return 0; // 然后就 AC 了、
    }
    
  • 相关阅读:
    not(expr|ele|fn)从匹配元素的集合中删除与指定表达式匹配的元素
    has(expr|ele)保留包含特定后代的元素,去掉那些不含有指定后代的元素。
    map(callback)将一组元素转换成其他数组(不论是否是元素数组)
    is(expr|obj|ele|fn)
    filter(expr|obj|ele|fn)筛选出与指定表达式匹配的元素集合。
    eq(index|-index)
    clone([Even[,deepEven]])克隆匹配的DOM元素并且选中这些克隆的副本。
    detach([expr]) 从DOM中删除所有匹配的元素。
    scrollTop([val])
    offset([coordinates])
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-cqoi2009_lg1627.html
Copyright © 2011-2022 走看看