2021杭电多校补题(5)
1. Array
题意:
给出一个长度为 n n n 的数组,求其有多少个区间满足其众数个数大于区间长度的一半。
题解:
考虑分治。
对于一个区间 ( l , r ) (l,r) (l,r),其中点为 m i d mid mid ,我们求出有多少个子区间包含 m i d mid mid 且满足题目要求。
首先来看一个性质:假设 v a l val val 为区间 ( x , y ) (x,y) (x,y)内满足要求的数,那么 v a l val val 必定也在区间 ( x , m i d ) (x,mid) (x,mid)或 ( m i d + 1 , y ) (mid+1,y) (mid+1,y) 中满足要求。
那么我们可以从 m i d mid mid 开始,先往左扩展,找到所有可能为答案的数,再往右扩展,也找到可能为答案的数。
然后枚举我们找到的数 x x x ,求有多少个区间满足条件的数为 x x x 。
把等于 x x x的数设为1,反之设为-1,先枚举左端点,碰到1则sum++,反之sum- -,那么sum>0说明区间是合法的。对sum值计数,并且维护其前缀和。
再接着枚举右端点,同样碰到1则sum++,反之sum- -,考虑右端点的答案,因为sum>0才是合法的,所以所以左端点的sum值为 ≤ s u m − 1 \leq sum-1 ≤sum−1 才行,所以直接加上前缀和即可。
代码
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e6+5;
const int inf=0x3f3f3f3f;
ll ans=0;
int a[MAXN];
int num[MAXN];//可能的数
int pre[MAXN];//出现次数
int vis[MAXN];
void solve(int l,int r)
{
if(l==r){
ans++;
return;
}
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
for(int i=mid;i>=l;i--){
pre[a[i]]++;
if(pre[a[i]]>(mid-i+1)/2){
if(!vis[a[i]]){
num[0]++;
num[num[0]]=a[i];
vis[a[i]]=1;
}
}
}
for(int i=mid;i>=l;i--){
pre[a[i]]=0;
}
for(int i=mid+1;i<=r;i++){
pre[a[i]]++;
if(pre[a[i]]>(i-mid)/2){
if(!vis[a[i]]){
num[0]++;
num[num[0]]=a[i];
vis[a[i]]=1;
}
}
}
for(int i=l;i<=r;i++){
vis[a[i]]=0;
pre[a[i]]=0;
}
for(int i=1;i<=num[0];i++)
{
int sum=r-l+1,maxx=r-l+1,minn=r-l+1;
pre[sum]=1;
for(int j=l;j<mid;j++)
{
if(a[j]==num[i])
{
sum++;
}
else
{
sum--;
}
pre[sum]++;
maxx=max(maxx,sum);
minn=min(minn,sum);
}
if(a[mid]==num[i])
{
sum++;
}
else sum--;
for(int j=minn;j<=maxx;j++){
pre[j]+=pre[j-1];
}
for(int j=mid+1;j<=r;j++)
{
if(a[j]==num[i])
{
sum++;
}
else
{
sum--;
}
ans+=pre[min(sum-1,maxx)];
}
for(int j=minn;j<=maxx;j++){
pre[j]=0;
}
}
num[0]=0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
ans=0;
solve(1,n);
printf("%lld\n",ans);
}
}

浙公网安备 33010602011771号