[分塊 隨機Hash] Romanian IOI 2017 Selection #6 Jolteon

傳送門

問有多少個區間,出現過的數出現次數都是奇數
給每個數隨機一個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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章