Codeforces1005E1 - Median on Segments (Permutations Edition)(中位数计数)

原题链接:https://vjudge.net/problem/1663377/origin

 题解:

先看如何判断一个数是否为中位数:

如果这个数m,比它大的和比它小的数是一样多的,那么它就是中位数。

在这个题里,n个数是不重复而且连续的,那么以m为中位数的子序列必定含有m,

所以我们先找到m的位置,立个flag,从flag右边开始枚举,如果枚举的数大于m,cnt就加1,否则就减1;

建个数组vis来存大于m与小于m的数之差。

再枚举左边的数,如果枚举的数大于m,cnt减一,小于m,cnt+1,这样当左右两边综合考虑时,当大于m与小于m的数一样多时,vis里面的数就是以m为中位数的区间个数。

具体见代码注释。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn=5e5+10;
int a[maxn*2];
int vis[maxn*2];
int main()
{
	int m,n,flag,cnt=0;
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		if(a[i]==m)
		{
			flag=i;
		}
		}
	for(int i=flag;i<n;i++)//往右边开始枚举 
	{
		if(a[i]>m)
		{
			cnt++;
		}
		if(a[i]<m)
		{
			cnt--;
		}
		vis[maxn+cnt]++;//因为cnt可能是负数,所以加个maxn防止数组索引出现负数
	}
	long long int sum=0;
	cnt=0;
	for(int i=flag;i>=0;i--)
	{
		if(a[i]>m)
		{
			cnt--;
		}
		if(a[i]<m)
		{
			cnt++;
		}
		sum+=vis[maxn+cnt];
		sum+=vis[maxn+cnt+1];//偶数就加一,不懂的话,具体过程可自行模拟一下就很容易理解 
	}
	cout<<sum<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/csustudent007/article/details/81098107