[Hash] 2017 计蒜之道 初赛 第五场 UCloud 的安全秘钥

判断两个可重集是否相同,给每个元素一个随机的 64 位无符号整数权值,然后全部加起来作为集合的 Hash 值。那么一个子串的 Hash 值可以简单地由前缀和作差得到,每次检验的复杂度为O(1)。

其实只要一个观察 询问中不同的长度只有 O(len)
map竟然T了 smg

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<map>
#define pb push_back
using namespace std;
typedef unsigned long long ull;
typedef pair<ull,int> abcd;

#define read(x) scanf("%d",&(x))

const int N=200005;

int n,m,s[N];
ull a[N],H[N];
vector<abcd> v[N];
int ans[N];


const int _P=1000007;
const int _N=1000005;
struct HashMap{
  int head[_P],inum,clk;
  int tag[_P];
  ull h[_N]; int g[_N],next[_N];
  void _new(){
    ++clk; inum=0;
  }
  int Head(int x){
    return tag[x]!=clk?(tag[x]=clk,head[x]=0):head[x];
  }
  int &at(ull _h){
    int hs=_h*233%_P;
    for (int p=Head(hs);p;p=next[p])
      if (h[p]==_h)
    return g[p];
    h[++inum]=_h; g[inum]=0; next[inum]=head[hs]; head[hs]=inum;
    return g[inum];
  }
}Map;

int main(){
  srand(10086);
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); for (int i=1;i<=n;i++) a[i]=((ull)rand()<<32)+rand();
  for (int i=1;i<=n;i++) read(s[i]),H[i]=H[i-1]+a[s[i]];
  read(m);
  for (int i=1;i<=m;i++){
    int k,x; ull h=0;
    read(k);
    for (int j=1;j<=k;j++) read(x),h=h+a[x];
    v[k].pb(abcd(h,i));
  }
  for (int i=1;i<=n;i++)
    if (v[i].size()){
      sort(v[i].begin(),v[i].end());
      Map._new();
      for (int j=1;j+i-1<=n;j++)
    Map.at(H[j+i-1]-H[j-1])++;
      for (int j=0;j<v[i].size();j++)
    ans[v[i][j].second]=Map.at(v[i][j].first);
    }
  for (int i=1;i<=m;i++)
    printf("%d\n",ans[i]);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值