1303: [CQOI2009]中位数图
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3009 Solved: 1860
[ Submit][ Status][ Discuss]
Description
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
Input
第一行为两个正整数n和b ,第二行为1~n 的排列。
Output
输出一个整数,即中位数为b的连续子序列个数。
Sample Input
7 4
5 7 2 4 3 1 6
5 7 2 4 3 1 6
Sample Output
4
HINT
第三个样例解释:{4}, {7,2,4}, {5,7,2,4,3}和{5,7,2,4,3,1,6}
N<=100000
Source
切BZOJ的题真的是爽啊233333
这么短的题目我就不解释题目了
把所有小于 b 的数字当作 -1,所有大于 b 的数字当作 1,等于 b 的当作 0。
然后就得到了一个新的序列
对这个序列做一个前缀和
以 b 所在的位置当作分界线
当左边的有数字和右边的数字相等的时候
那就构成一组答案
以样例为例
5 7 2 4 3 1 6
构成的新序列就是: 1 1 -1 0 -1 -1 1
得到前缀和(要补零)
0 1 2 1
1 0 -1 0
然后以 b 为分界线
统计一下 b 的两边有多少组相同的数字就 OK 了(即蓝红两色)
用桶排的思想 O(n) 能实现
不过要记得消除负数
也可以直接用 map
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int vis[N * 5];
int main(int argc, char const *argv[])
{
int n, m;
int sum;
int mark;
int ans;
while(scanf("%d%d", &n, &m) == 2){
memset(vis, 0, sizeof(vis));
ans = 0;
mark = 0;
sum = 0;
vis[0 + N] = 1;
for(int i = 1; i <= n; i ++){
int x;
scanf("%d", &x);
if(x > m){
sum ++;
}
else if(x == m){
mark = 1;
}
else{
sum --;
}
if(!mark){
vis[sum + N] ++;
}
else{
if(vis[sum + N]){
ans += vis[sum + N];
}
}
}
printf("%d\n", ans);
}
return 0;
}