zoukankan      html  css  js  c++  java
  • 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); 
    }
    

      

  • 相关阅读:
    二分制--找最小值去重
    angular过滤 排序问题
    div+css背景渐变色代码
    angular中对象与字符串之间的转换
    AMD模块
    jquery.validate
    谈谈js中深度克隆和浅度克隆
    还在使用git吗?不妨来看看如何使用git管理版本
    闭包
    js复习
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15153175.html
Copyright © 2011-2022 走看看