[分块 随机Hash] Romanian IOI 2017 Selection #6 Jolteon

20 篇文章 0 订阅

传送门

问有多少个区间,出现过的数出现次数都是奇数
给每个数随机一个hash值
然后区间中所有数的xor和 和 所有 pre<lir 的数的异或和 相同
那么就合法
枚举右端点,新增一个数会对一段造成影响
变成区间异或,区间是否存在一个数,分块维护

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;
const int BB=405;

const int maxn=1000000;
int last[maxn+5]; ull S[maxn+5];

int n,a[N],pre[N];

int B,pos[N],cnt,lp[BB],rp[BB],size[BB];

const int P=20007;

ull H[BB][BB];

struct HashMap{
  ull h[BB]; int cnt[BB],next[BB];
  int head[P],vst[P],inum;
  int clk; 
  void _new(){ ++clk; inum=0; }
  int &Head(int x){
    return vst[x]!=clk?(vst[x]=clk,head[x]=0):head[x];
  }
  int& operator[](ull x){
    int hh=x%P;
    for (int p=Head(hh);p;p=next[p])
      if (h[p]==x)
    return cnt[p];
    int p=++inum; h[p]=x; cnt[p]=0; next[p]=head[hh]; head[hh]=p;
    return cnt[p];
  }
  int find(ull x){
    int hh=x%P;
    for (int p=Head(hh);p;p=next[p])
      if (h[p]==x)
    return cnt[p];
    return 0;
  }
}Map[BB];

ull tag[BB];

inline void Build(int n){
  B=(int)min(sqrt(n)+1,(double)n);
  for (int i=1;i<=n;i++) pos[i]=(i-1)/B+1; cnt=pos[n];
  for (int i=1;i<=cnt;i++) lp[i]=(i-1)*B+1,rp[i]=i*B; rp[cnt]=n;
  for (int i=1;i<=cnt;i++) size[i]=rp[i]-lp[i]+1;
  ull sum=0;
  for (int i=1;i<=n;i++){
    int b=pos[i];
    H[b][i-lp[b]+1]=sum; Map[b][sum]++;
    sum^=S[a[i]];
  }
}

inline void Add(int l,int r,ull t){
  int lb=pos[l],rb=pos[r];
  if (lb==rb){
    Map[lb]._new();
    for (int i=l-lp[lb]+1;i<=r-lp[lb]+1;i++) H[lb][i]^=t;
    for (int i=1;i<=size[lb];i++) Map[lb][H[lb][i]^=tag[lb]]++;
    tag[lb]=0;
    return;
  }
  for (int i=lb+1;i<rb;i++) tag[i]^=t;

  Map[lb]._new();
  for (int i=l-lp[lb]+1;i<=size[lb];i++) H[lb][i]^=t;
  for (int i=1;i<=size[lb];i++) Map[lb][H[lb][i]^=tag[lb]]++;
  tag[lb]=0;

  Map[rb]._new();
  for (int i=1;i<=r-lp[rb]+1;i++) H[rb][i]^=t;
  for (int i=1;i<=size[rb];i++) Map[rb][H[rb][i]^=tag[rb]]++;
  tag[rb]=0;
}
inline int Query(int r,ull t){
  int rb=pos[r],ret=0;
  for (int i=1;i<rb;i++)
    ret+=Map[i].find(t^tag[i]);
  for (int i=1;i<=r-lp[rb]+1;i++)
    ret+=((H[rb][i]^tag[rb])==t);
  return ret;
}

int icnt,sx[N];
inline int Bin(int x){
  return lower_bound(sx+1,sx+icnt+1,x)-sx;
}

int main(){
  freopen("gf.in","r",stdin);
  freopen("gf.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) read(a[i]),sx[++icnt]=a[i];
  sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
  for (int i=1;i<=n;i++){
    a[i]=Bin(a[i]);
    pre[i]=last[a[i]],last[a[i]]=i;
  }
  for (int i=1;i<=icnt;i++) S[i]=((ull)rand()<<48)|((ull)rand()<<32)|((ull)rand()<<16)|((ull)rand());
  ll ans=0; ull sum=0; Build(n);
  for (int i=1;i<=n;i++){
    Add(pre[i]+1,i,S[a[i]]); sum^=S[a[i]];
    ans+=Query(i,sum);
  }
  printf("%lld\n",ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值