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); }