[POI2015] POD - 洛谷
核心 思路
考察了哈希异或的妙用,可以相互抵消掉。
注意到,设计一个Hash函数,维护前缀异或和。
双指针让 r 找大于 n 一半的位置。
合理,则更新答案
AC 代码
#include<bits/stdc++.h>
using namespace std;
int n,k,ansx=0x3f3f3f3f,tot,siz;
long long ans,a[1000005],tmp;
vector<int>v[1000005];
unordered_map<long long,int>mp;//使用 map<long long,vector<int>> 会爆空间
mt19937 rng(time(0));
uniform_int_distribution<long long>gen(1,0x3f3f3f3f3f3f3f3f);//随机数
int main(){
ios::sync_with_stdio(0);
cin>>n>>k;
for(int i = 1;i <= n;i++){
cin>>a[i];
v[a[i]].push_back(i);
}
for(int i = 1;i <= k;i++){
tmp = 0,siz = v[i].size();
for(int j = 0;j <= siz-2;j++){
a[v[i][j]] = gen(rng),tmp^=a[v[i][j]];
}
a[v[i][siz-1]] = tmp;
v[i].clear();
}
for(int i = 1;i <= n;i++){
a[i]^=a[i-1];
if(!mp.count(a[i])){
mp[a[i]] = ++tot;
}
v[mp[a[i]]].push_back(i);
}
for(int i = 1;i <= tot;i++){
siz = v[i].size(),ans+=1ll*siz*(siz-1)/2;
for(int l = 0,r = 1;r < siz&&l<r;l++){
while(r<siz&&2*(v[i][r]-v[i][l])<=n)r++;
if(l<r-1)
ansx=min(ansx,n-2*(v[i][r-1]-v[i][l]));
if(r<siz)
ansx=min(ansx,2*(v[i][r]-v[i][l])-n);
}
}
cout<<ans<<' '<<ansx;
return 0;
}