P8313 [COCI 2021/2022 #4] Izbori
首先观察部分分,对于前两组部分分,可以直接暴力枚举左右端点。
对于第三组部分分,从前缀和的角度去思考,然后可以发现假设一个数字为正数,一个数字为负数,开桶进行统计,只要两种人数不打平即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[200005],tmp[200005],cnt,t[400005],ans;
void solve(){
int tmp=0;
for(int i=1;i<=n;i++){
t[tmp+n+1]++;
if(a[i]==2)tmp++;
else tmp--;
ans+=i-t[tmp+n+1];
}
cout<<ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)tmp[i]=a[i];
sort(tmp+1,tmp+n+1);
cnt=unique(tmp+1,tmp+n+1)-tmp-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
if(cnt<=2){
solve();
return 0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt;j++)t[j]=0;
int ma=0;
for(int j=i;j<=n;j++){
t[a[j]]++;
ma=max(ma,t[a[j]]);
if(ma>(j-i+1)/2)ans++;
}
}
cout<<ans;
return 0;
}
考虑怎么解决最后的问题。
观察前面的部分分做法,我们会很想枚举所有的种类进行处理,但是这样的种类实在是太多了。
我们可以考虑使用分治。
我们利用分治来解决,但是这样枚举的数字数量依然很大,但是我们还可以发现,实际上有效的数字并不多。
由于左端点位置确定在右边,左端点位置确定在左边部分,所以我们可以想到对于每一个有效点,仅在此点到中点时还满足条件,那么这个点可行。
可行的点有多少个?实际上最多只有 \(\log(n)\) 个,因为每个点要到达中点最少需要数量达到总数量一半以上,最后相当于多个二的幂次相加。
那么我们只需要在分治中预处理,预处理完以后再用前缀和进行统计即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[200005],ans,tmp[200005],cnt,t[200005],vis[200005],pre[400005];
vector<int> v;
void solve2(int x,int l,int r){
int mid=l+r>>1;
int tmp=n+1,mi=n+1,ma=n+1;
pre[n+1]=1;
for(int i=l;i<=mid-1;i++){
if(a[i]==x)tmp++;
else tmp--;
pre[tmp]++;
mi=min(mi,tmp),ma=max(ma,tmp);
}
if(a[mid]==x)tmp++;
else tmp--;
for(int i=mi+1;i<=ma;i++)pre[i]+=pre[i-1];
for(int i=mid+1;i<=r;i++){
if(a[i]==x)tmp++;
else tmp--;
if(tmp>ma)ans+=pre[ma];
else if(tmp>=mi)ans+=pre[tmp-1];
}
for(int i=mi;i<=ma;i++)pre[i]=0;
}
void solve(int l,int r){
if(l==r)return void(ans++);
int mid=l+r>>1;
solve(l,mid),solve(mid+1,r);
for(int i=l;i<=mid;i++){
t[a[i]]++;
if(t[a[i]]*2>mid-i+1&&!vis[a[i]])v.push_back(a[i]),vis[a[i]]=1;
}
for(int i=l;i<=mid;i++)t[a[i]]=0;
for(int i=mid+1;i<=r;i++){
t[a[i]]++;
if(t[a[i]]*2>i-mid&&!vis[a[i]])v.push_back(a[i]),vis[a[i]]=1;
}
for(int i=mid+1;i<=r;i++)t[a[i]]=0;
for(int i=l;i<=r;i++)vis[a[i]]=0;
for(int i:v)solve2(i,l,r);
v.clear();
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)tmp[i]=a[i];
sort(tmp+1,tmp+n+1);
cnt=unique(tmp+1,tmp+n+1)-tmp-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
solve(1,n);
cout<<ans;
return 0;
}

浙公网安备 33010602011771号