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;
}