BZOJ 1303-中位数图(中位数技巧)

来源:互联网 发布:知乎 高中生 编辑:程序博客网 时间:2024/05/17 08:44

1303: [CQOI2009]中位数图

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


感觉与中位数有关的题都是各种技巧啊,好难想啊,还是看的题解的(5555.。。)

  1. 若a[i]<b,则c[i]=-1。
  2. 若a[i]=b,则c[i]=0,用一个变量wz记录当前的i。
  3. 若a[i]>b,则c[i]=1。
    这样我们就把题目转化成了求c数组里有多少子序列的和为0。

    之后我们再对c数组做一遍前缀和,然后枚举两个位置i和j,设i<j,若c[i]=c[j],则答案+1。

    因此,我们设k=0->wz-1,统计每个c[k]的出现次数,然后再设k=wz->n,ans+=c[k]出现的次数。

    为了防止c[k]为下标时c[k]<0,不符合C++语言,因此我们可以把c[k]+=n。


#include<map>#include<stack>#include<queue>#include<vector>#include<math.h>#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include<algorithm>using namespace std;typedef long long  ll;#define inf 10000000#define mod 1000000007 #define  maxn  200005#define  eps 1e-10int a[maxn],b[maxn];int main(void){int n,m,i,j,x,ans=0,p;scanf("%d%d",&n,&m);for(i=1;i<=n;i++){scanf("%d",&x);if(x<m)b[i]=-1;if(x==m)b[i]=0,p=i;if(x>m)b[i]=1;b[i]+=b[i-1];}for(i=0;i<p;i++)a[b[i]+n]++;for(i=p;i<=n;i++)ans+=a[b[i]+n];printf("%d\n",ans);return 0;}