[分块][哈希] [Romanian IOI 2017 Selection #6] Jolteon && [LOJ #6187] Odd

博客介绍了在解决LOJ #6187(Odd)问题时,如何运用哈希和分块技术。内容提及该问题与CF77F相似,但因数据特性需采用不同策略。博主分享了因哈希错误导致的一晚调试经历,暗示题目对数据处理的严谨性要求较高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在loj上看到的题,跟CF77F差不多
但是这不是一个线段,而是一些数字,就不能用同样的方法hash,问了大佬Manchery,恰好他一周前做过……传送门

不过loj上数据更强吧…我Hash打错调了一晚上……

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#define fi first
#define se second

using namespace std;

const int N=200010,P=100003;

typedef unsigned long long ull;
typedef pair<ull,int> par;

int n,block;
int a[N],lst[N*5];
ull val[N],Hash[N*5];

inline int Hash_(ull x){
  return x%P;
}

struct Hst{
  ull tag;
  Hst(){ tag=cnt=bnt=0; }
  int H[P+5],nxt[550],bin[550],bnt,cnt;
  par key[550];
  void insert(ull x){
    int u=Hash_(x);
    for(int i=H[u];i;i=nxt[i])
      if(key[i].fi==x){ key[i].se++; return ; }
    int cur=bnt?bin[bnt--]:++cnt;
    key[cur]=par(x,1); nxt[cur]=H[u]; H[u]=cur;
  }
  void erase(ull x){
    int u=Hash_(x),v=0,l=0;
    for(int i=H[u];i;l=i,i=nxt[i])
      if(key[i].fi==x) { v=i; break; }
    if(!v) return ; --key[v].se;
    if(key[v].se) return ;
    if(l) nxt[l]=nxt[v]; else H[u]=nxt[v];
    bin[++bnt]=v;
  }
  int count(ull x){
    x^=tag; int u=Hash_(x);
    for(int i=H[u];i;i=nxt[i])
      if(key[i].fi==x) return key[i].se;
      return 0;
  }
}T[550];

void Modify(int l,int r,ull flg){
  int L=l/block,R=r/block;
  if(L==R){
    for(int i=l;i<=r;i++)
      T[L].erase(val[i]),T[L].insert(val[i]^=flg);
    return ;
  }
  for(int i=L+1;i<R;i++) T[i].tag^=flg;
  for(int i=l;i<(L+1)*block;i++)
    T[L].erase(val[i]),T[L].insert(val[i]^=flg);
  for(int i=R*block;i<=r;i++)
    T[R].erase(val[i]),T[R].insert(val[i]^=flg);
}

int Query(int r,ull tar){
  int ret=0,R=r/block;
  for(int i=0;i<R;i++)
    ret+=T[i].count(tar);
  for(int i=R*block;i<=r;i++)
    if((val[i]^T[R].tag)==tar) ret++;
  return ret;
}

int main(){
  scanf("%d",&n); block=sqrt(n);
  for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    if(!Hash[a[i]]) Hash[a[i]]=1LL*rand()*rand()*rand();
  }
  T[0].insert(0); val[0]=0;
  long long ans=0; ull pre=0;
  for(int i=1;i<=n;i++){
    val[i]=(pre^=Hash[a[i]]);
    T[i/block].insert(val[i]);
    Modify(lst[a[i]],i-1,Hash[a[i]]); lst[a[i]]=i;
    ans+=Query(i-1,pre);
  }
  cout<<ans<<endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值