[CQOI2009] 中位数

题目描述

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

输入格式

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

输出格式

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

样例 #1

样例输入 #1

1
2
7 4
5 7 2 4 3 1 6

样例输出 #1

1
4

提示

数据规模与约定

对于 $30\%$ 的数据中,满足 $n \le 100$;

对于 $60\%$ 的数据中,满足 $n \le 1000$;

对于 $100\%$ 的数据中,满足 $n \le 100000,1 \le b \le n$。

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <map>
#define LL long long

using namespace std;

int n,b,p[100010]{},k,suml,sumr;
LL sum;
map<int,int> mp;

int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> b;
for(int i=1;i<=n;i++){
cin >> p[i];
if(p[i] == b) k = i;
}
for(int i=k;i<=n;i++){
if(p[i] > b) ++suml;
else if(p[i] < b) --suml;
++mp[suml];
}
for(int i=k;i>=1;i--){
if(p[i] > b) ++sumr;
else if(p[i] < b) --sumr;
sum += mp[0-sumr];
}
cout << sum;
return 0;
}

思路分析

主要思路把数据的大小转化为是否比b大,从而把数据转换为1/0/-1的形式,接着进行前缀和和后缀和的相加,顺便把数据存进map里,因为可能会出现负数。这样的话时间复杂度是O(nlogn)而不是O(n)了,可以把桶开大点,然后负数也可以存了,那么时间复杂度就是O(n)了,例如

1
int p[2e5+100]//这里就可以把初始值设置成1e5 p[0]->p[1e5] p[-5]->p[1e5-5]

错误总结

  • 还是要记得数据范围别炸int哩!
  • 第一第二次投了都没过,最后发现自己把循环变量和b的位置搞混了= =