Loading

nowcoder11166H Hash Function(2021牛客暑期多校训练营1) fft

题意

给定一个集合\(S=\{a_0,a_1,a_2,\dots a_{n-1}\}\),和一个哈希函数\(h_{seed}(x)=x\%seed\)。找出最小的\(seed\)使得集合\(S\)不出现哈希冲突。(\(1\le n\le5*{10}^5,0\le a_i\le5*{10}^5\)

思路

出现哈希冲突等价于\(seed\mid abs(a_i-a_j)\)。可以找出所有差的取值,然后再检查每个\(seed\)的倍数是否对应两数之差即可。所有差的取值可以通过\(x^{max(a_i)}(x^{-a_0}+x^{-a_1}+x^{-a_2}+\dots+x^{-a_{n-1}})(x^{a_0}+x^{a_1}+x^{a_2}+\dots+x^{a_{n-1}})\)卷积得到。

代码

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
constexpr int N(6e5+5);
int a[N],f[N*2],g[N*2];

constexpr int P(998244353),G(3);
int mpow(ll a,ll b=P-2) {
  ll ans=1;
  for(;b;b>>=1,a=a*a%P)
    if(b&1) ans=ans*a%P;
  return ans;
}
void dft(int* a,int n,bool idft=false) {
  vector<int>inv(n);
  for(int i=1;i<n;i++) {
    inv[i]=inv[i/2]/2+(n/2)*(i&1);
    if(i<inv[i]) swap(a[i],a[inv[i]]);
  }
  for(int i=1;i<n;i*=2) {
    int w0=mpow(G,(P-1)/(2*i));
    if(idft) w0=mpow(w0);
    for(int j=0;j<n;j+=2*i) {
      int w=1;
      for(int k=0;k<i;k++,w=1ll*w*w0%P) {
        int t=1ll*a[j+k+i]*w%P;
        a[j+k+i]=(a[j+k]-t+P)%P;
        a[j+k]=(a[j+k]+t)%P;
      }
    }
  }
  if(idft) {
    int invn=mpow(n);
    for(int i=0;i<n;i++)
      a[i]=1ll*a[i]*invn%P;
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n,mx=0;
  cin>>n;
  for(int i=0;i<n;i++) {
    cin>>a[i];
    mx=max(mx,a[i]);
  }
  for(int i=0;i<n;i++) {
    f[a[i]]=1;
    g[mx-a[i]]=1;
  }
  int N=1<<(__lg(2*mx)+1);
  dft(f,N);dft(g,N);
  for(int i=0;i<N;i++)f[i]=1ll*f[i]*g[i]%P;
  dft(f,N,1);
  
  for(int i=1;i<=mx+1;i++) {
    bool flag=false;
    for(int j=i;j<=mx;j+=i)
      if(f[mx+j]) flag=true;
    if(!flag) {
      cout<<i<<'\n';
      break;
    }
  }
  return 0;
}
posted @ 2021-07-21 14:12  intmian  阅读(49)  评论(0编辑  收藏  举报