牛客网【每日一题】5月22日 [CQOI2009]中位数图

链接:

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

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

输入描述:

第一行为两个正整数n和b ,第二行为1~n 的排列

输出描述:

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

示例1
输入

7 4
5 7 2 4 3 1 6

输出

4

题解:

b是中位数,在b后面的比b大,前面的比b小,比b大多少小多少都无所谓,所以我们可以把大于b的数记为1,小于的记为-1,相等的记为0,这样的话,我们要找一个什么样的区间?一个奇数区间的和是0且0的长度还是奇数(和为0说明左右两边-1和1数量相等,且最中间为0是我们所要的b)
我们可以以0开始分别分析左右两边,统计0的左边后缀和为i的个数,右边的前缀和为i的个数,为了保证两边数量相同,就要使右边的前缀和与左边的前缀和互为相反数。(左右前缀和均从0开始)
样例:
5 7 2 4 3 1 6
化为-1,0,1
1 1 -1 0 -1 -1 1
0的左边前缀和(从0开始)
1 0 -1
右边
-1 -2 -1

左边一个-1可以和右边两个-1搭配,两个答案
左边一个0,不与右边搭配,一个答案
b本身,一个答案
总:四个答案

代码:

(代码仅提供思路)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 1e6+4
using namespace std;
int a[maxn];
map<int,int >b;
int main()
{
	int n,m;
	cin>>n>>m;
	int pos,sum=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(a[i]<m)a[i]=-1;
		else if(a[i]>m)a[i]=1;
		else 
		{
			a[i]=0;
			pos=i;
		}
	}
	b[0]=1;//和为0则符合条件 
	int tot=0;
	for(int i=pos-1;i;i--)
	{
		if(a[i]==1)sum--;//前缀和 
		else sum++;
		if(sum==0)tot++;//存在0就直接加 
		b[tot]++;
	}
	for(int i=pos+1;i<=n;i++)
	{
		if(a[i]==1)sum--;
		else sum++:
			ans+=b[-sum];//查看相反数有多少个 
	}
	printf("%d",tot);
	return 0;
}
posted @ 2020-05-28 11:06  回归梦想  阅读(64)  评论(0编辑  收藏  举报