P8313 [COCI 2021/2022 #4] Izbori 题解
题意,即求有多少区间存在绝对众数。考虑分治,每次求经过 \(mid\) 的好区间的个数。
注意到若 \([l,r]\) 存在绝对众数,则 \([l,mid]\) 或 \([mid+1,r]\) 必有一个存在绝对众数。固定一个端点,绝对众数的个数是 \(\mathcal O(\log n)\) 的。
于是可以处理出所有可能的绝对众数,令这个数为 \(+1\),其它数为 \(-1\),从 \(mid\) 往两边求和,对于某一边统计一个前缀和,另一边直接 \(\mathcal O(1)\) 求个数。
时间复杂度 \(\mathcal O(n\log^2 n)\)。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,mx,a[mxn],b[mxn],c[mxn];
ll ans;
set<int>s;
void solve(int l,int r){
if(l==r){
ans++;
return;
}
int mid=(l+r)>>1;
solve(l,mid);solve(mid+1,r);
s.clear();
drep(i,mid,l)c[a[i]]=0;
c[mx=0]=0;
drep(i,mid,l){
if(++c[a[i]]>c[mx])mx=a[i];
if(c[mx]>(mid-i+1)>>1)s.insert(mx);
}
c[mx=0]=0;
rep(i,mid+1,r)c[a[i]]=0;
rep(i,mid+1,r){
if(++c[a[i]]>c[mx])mx=a[i];
if(c[mx]>(i-mid)>>1)s.insert(mx);
}
for(int cl:s){
int ct=0;
rep(i,0,((r-mid)<<1)+1)c[i]=0;
rep(i,mid+1,r){
ct+=a[i]==cl?1:-1;
c[ct+r-mid]++;
}
drep(i,(r-mid)<<1,0)c[i]+=c[i+1];
ct=0;
drep(i,mid,l){
ct+=a[i]==cl?1:-1;
if(1-ct+r-mid<=(r-mid)<<1)ans+=c[max(1-ct+r-mid,0)];
}
}
}
signed main(){
scanf("%d",&n);
rep(i,1,n)scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
rep(i,1,n)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
solve(1,n);
cout<<ans;
return 0;
}

浙公网安备 33010602011771号