nowcoder11166H Hash Function(2021牛客暑期多校訓練營1) fft
阿新 • • 發佈:2021-07-21
題意
給定一個集合\(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; }