loj#6187. Odd

upt:由于是异或,正确性不一定能保证。可以考虑对每个权值随机赋值加强正确性。

首先有个性质,假如这个区间合法,那么这个区间的异或和等于这个区间出现过的数的异或和。

出现过的数自然想到 HH 的项链,考虑记 $las$,然后一个数只对 $[las_{a[i]}+1,i]$ 有贡献。

记 $ s_i=v[1] xor  v[2] xor ...  v[i]$ 即前缀异或和。

$sum1$ 为区间出现过的数的异或和。

 那么,答案就是 $s_y  xor   s_{x-1} = sum1_{x->y}$,转换下 $ s_y=sum1{x->y} xor s_{x-1}$,即找多少个 $xor$ 起来与 $s_y$ 相等的。

如何维护 $sum1$ 呢,对于一个数 $a[i]$,它对左端点影响区间是 $[las_{a[i]}+1,i]$(因为我们查找就是找 $x$,注意是端点不是区间,区间的话需要再抵消上一次的贡献,我们要让这整个端点区间异或上 $val[a[i]]$(因为查找就是找 $[x,y]$ $y$ 是当前枚举的,$xin [1,y]$)。对于 $s_{x-1}$ 我们可以考虑就是它本来的权值。

考虑 $s_y$ 可能很大,需要用 $hash$ 查找,发现可以用分块,对于每个块开一个 $hash$ 表,整个序列初始权值为 $s_{i-1}$,然后其他操作显然。

我的代码应该是最劣解 /cy

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <ctime>

#define ll long long
using namespace std;
int rd() {
	int f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
ll lrd() {
	ll f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
const int N=(int)(2e5+5),M=(int)(1e6+5),B=500,mod=4991;
ll s[N],val[M],id[N],L[B],R[B],tag[B],Bsum[N];
int a[N],las[M],n,bl=450;

struct HASH {
	struct node {
		int cnt,nex; ll val;
	}H[mod+2];
	int head[mod+2],tot;
	void clear() {
		tot=0; memset(head,0,sizeof(head));
	}
	int Find(ll x) {
		for(int i=head[x&mod];i;i=H[i].nex) if(H[i].val==x) return i;
		return -1;
	}
	int query(ll x) {
		int h=Find(x);
		if(~h) return H[h].cnt;
		return 0;
	}
	void ins(ll x) {
		int h=Find(x);
		if(~h) ++H[h].cnt;
		else {
			H[++tot].cnt=1; H[tot].nex=head[x&mod]; H[tot].val=x; head[x&mod]=tot;
		}
	}
}Hash[B];

ll get_rand() {
	return (1ll*rand()<<31|rand());
}

void build(int x) {
	Hash[x].clear();
	for(int i=L[x];i<=R[x];i++) Bsum[i]^=tag[x],Hash[x].ins(Bsum[i]); tag[x]=0;
}

void update(int l,int r,ll v) {
	if(id[l]==id[r]) {
		for(int i=l;i<=r;i++) Bsum[i]^=v;
		build(id[l]); 
	} else {
		for(int i=l;i<=R[id[l]];i++) Bsum[i]^=v;
		for(int i=L[id[r]];i<=r;i++) Bsum[i]^=v;
		build(id[l]); build(id[r]);
		for(int i=id[l]+1;i<id[r];i++) tag[i]^=v;
	}
}

int query(int l,int r,ll v) {
	ll res=0;
	if(id[l]==id[r]) {
		build(id[l]); for(int i=l;i<=r;i++) res+=(Bsum[i]==v);
	} else {
		build(id[l]); build(id[r]);
		for(int i=l;i<=R[id[l]];i++) res+=(Bsum[i]==v);
		for(int i=L[id[r]];i<=r;i++) res+=(Bsum[i]==v);
		for(int i=id[l]+1;i<id[r];i++) res+=Hash[i].query((v^tag[i]));
	}
	return res;
}

int main() { 
//	freopen("odd5.in","r",stdin); 
	srand(time(0));
	int mx=0; n=rd();
	for(int i=1;i<=n;i++) a[i]=rd(),id[i]=(i-1)/bl+1,mx=max(mx,a[i]);
	for(int i=0;i<=mx;i++) val[i]=get_rand();
	for(int i=1;i<=id[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n;
	for(int i=1;i<=id[n];i++) build(i);
	for(int i=1;i<=n;i++) Bsum[i]=s[i-1],s[i]=(s[i-1]^val[a[i]]);
	ll ans=0;
	for(int i=1;i<=n;i++) {
		update(las[a[i]]+1,i,val[a[i]]); las[a[i]]=i;
		ans+=query(1,i,s[i]);
	}
	printf("%lld",ans); 
}

  

原文地址:https://www.cnblogs.com/xugangfan/p/15153175.html