[BZOJ] 1303 - CQOI2009 - 中位數圖 - 思維 + 桶排序

1303: [CQOI2009]中位數圖

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 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

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


發佈了77 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章