【题解 P4062 & P8313】 Yazid 的新生舞会&Izbori

发布时间 2023-11-13 19:15:52作者: dijah

[COCI2021-2022#4] Izbori

题目描述

Malnar 先生正在竞选县长,这个县一共有 \(n\) 栋房屋,每栋房屋里都住着一位居民。Malnar 先生知道,选举的赢家不一定是最好的候选人,而是在选举前举办的宴会最好的候选人。因此,在选举前几天,他将邀请第 \(l\)\(r(l\le r)\) 栋房屋内居住的居民,为他们准备一顿丰盛的晚餐。

Malnar 先生知道所有居民最喜欢吃的菜。在宴会上,他会准备大多数人喜欢的一道菜。如果一个人吃到了自己最喜欢吃的菜,将会投一票给 Malnar 先生。但是如果没有吃到自己最喜欢吃的菜,他们将会把票投给 Vlado 先生。如果没有来参加晚宴的居民,他们将会忘记选举,不做出任何投票。如果一个候选人获得了投了票的人中一半以上的人的支持,他将会赢得竞选。

Malnar 先生想知道,有多少组的 \((l,r)\) 可以使他赢得竞选。

输入格式

第一行包含一个整数 \(n\),表示房屋的数量。

第二行包含 \(n\) 个整数 \(a_i\),表示第 \(i\) 栋房屋内居民最喜欢的菜。

输出格式

仅一行,输出可以使 Malnar 先生赢得竞选的 \((l,r)\) 的组数。

样例 #1

样例输入 #1

2
1 1

样例输出 #1

3

样例 #2

样例输入 #2

3
2 1 2

样例输出 #2

4

样例 #3

样例输入 #3

5
2 2 1 2 3

样例输出 #3

10

提示

【样例 2 解释】

可以使 Malnar 先生赢得竞选的 \((l,r)\) 为:\((1, 1),(2, 2),(3, 3),(1, 3)\)

【数据规模与约定】

本题采用子任务捆绑测试。

  • Subtask 1(10 pts):\(1 ≤ n ≤ 300\)
  • Subtask 2(15 pts):\(1 ≤ n ≤ 2\times10^3\)
  • Subtask 3(15 pts):\(\forall i\in\{1,2,3,\dots,n\},1 ≤ a_i ≤ 2\)
  • Subtask 4(70 pts):没有额外限制。

对于 \(100\%\) 的数据,\(1 \le l\le r ≤ n ≤ 2\times10^5,1 ≤ a_i ≤ 10^9\)

【提示与说明】

本题分值按 COCI 原题设置,满分 \(110\)

题目译自 COCI2021-2022 CONTEST #4 T3 Izbori。

解题思路

简明题意就是:找出满足一定条件的区间个数,每个区间需满足其中最大的数出现的次数严格大于区间长度的一半。
首先,我们可以考虑枚举每一个数,求出满足这个数在区间内出现次数大于区间长度一般的的区间个数,最后累加即可。
\(a_i\)\(1~i\) 中当前枚举数的出现个数,很明显,需要满足 \(a_r-a_{l-1}>(r-(l-1))/2\)
即为 \(2*a_r-r>2*a_{l-1}-(l-1)\)
这就是一个偏序问题了,时间复杂度 \(O(n^2logn)\)
考虑优化这个问题。
观察题目中找的是绝对众数,我们可以发现,从一个左端点开始找绝对众数,那么能成为绝对众数的数最多 \(log_{r-l+1}\) 个。
很容易理解,因为若要更新绝对众数,他是成倍增长的。
那么,我们就可以 \(cdq\) 分治了。
考虑左区间与右区间合并的贡献。
我们可以找出能成为绝对众数的数,最多 \(log_{r-l+1}\) 个,我们可以处理出这些数,然后按上面的方法求解偏序,加上单个数的贡献即可。
时间复杂度 \(O(nlog^2n)\)

Code

#include<bits/stdc++.h>
using namespace std;
int n,a[500005],d[500005],t[500005],w;
long long s=0;
bool cmp(int q,int w)
{
	return q>w;
}
void gaia(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)>>1;
	gaia(l,mid);
	gaia(mid+1,r);
	int x=0;
	w=0;
	for(int i=mid;i>=l;i--)
	{
		d[a[i]]++;
		if(d[a[i]]>(mid-i+1)/2)t[++w]=a[i];
	}
	for(int i=l;i<=mid;i++)d[a[i]]=0;
	for(int i=mid+1;i<=r;i++)
	{
		d[a[i]]++;
		if(d[a[i]]>(i-mid)/2)t[++w]=a[i];
	}
	for(int i=mid+1;i<=r;i++)d[a[i]]=0;
	sort(t+1,t+w+1);
	for(int i=1;i<=w;i++)
	{
		if(t[i]==t[i-1])continue;
		if(a[mid]==t[i])d[mid]=2+mid;
		else d[mid]=mid;
		for(int j=mid-1;j>=l;j--)
		{
			d[j]=d[j+1]-1;
			if(a[j]==t[i])d[j]+=2;
		}		
		sort(d+l,d+mid+1,cmp);
		if(a[mid+1]==t[i])d[mid+1]=mid;
		else d[mid+1]=mid+2;
		for(int j=mid+2;j<=r;j++)
		{
			d[j]=d[j-1]+1;
			if(a[j]==t[i])d[j]-=2;
		} 
		sort(d+mid+1,d+r+1,cmp);
		x=l-1;
		for(int j=mid+1;j<=r;j++)
		{
			while(x<mid&&d[x+1]>d[j])x++;
			s+=x-l+1;
		}
		for(int j=l;j<=r;j++)d[j]=0;
	}
	return;
}
int m;
set<int> l;
map<int,int> p;
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		l.insert(a[i]);
	}
	int g=0;
	set<int>::iterator q=l.begin();
	for(;q!=l.end();q++)
	{
		p[*q]=++g;
	}
	for(int i=1;i<=n;i++)a[i]=p[a[i]];
	gaia(1,n);
	cout<<s+n;








  return 0;
}