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;
}