[牛客多校]第一场H.Hash Function
题意:定义哈希函数\(h_{seed}(x) = x \mod{seed}\),给定一个集合,要求找到一个最小的\(seed\),使得集合内的数字哈希函数两两不同。
数据范围:\(n\le 5\times 10^5, a_i\le 5\times 10^5\)
注意到两个数字的哈希函数当且仅当$seed | (a_i - a_j) \(,假如我们知道每一个\)(a_i -a _j)\(是否存在,我们枚举每个\)seed\(,然后判断\)seed\(的每个倍数是否存在,这个过程是\)O(nlogn)$的,因为调和级数。
于是问题变成怎么快速求出每个\((a_i - a_j)\)是否存在。
\(f(i)\)表示\(i\)是否存在,反转整个数组,变成\(g(x) = f(500000 - x)\),然后跟原数组卷积,我们发现卷积\(h(x) = \sum f(i) * f(50000 - x - i)\),\(f(i),f(50000 - x - i)\)都不为\(0\)的时候对数组有贡献,表示存在这样的一个\((a_i - a_j)\)。
于是NTT随便卷一下就行了。
#include <bits/stdc++.h>
#define pt(x) cout << x << endl;
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read() {
char c; int num, f = 1;
while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
return f * num;
}
const int P = 998244353, G = 3, Gi = 332748118;
const int N = 5e5, M = N * 5 + 1009;
int n, A[M], B[M];
int Pow(int a, int p) {
int ans = 1;
for( ; p; p >>= 1, a = 1ll * a * a % P)
if(p & 1)
ans = 1ll * a * ans % P;
return ans % P;
}
namespace Polynomial {
const double Pi = acos(-1.0);
int rev[M];
template <typename T>
void change(T *y, int n) {
for(int i = 0; i < n; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (n >> 1) : 0);
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(y[i], y[rev[i]]);
}
void NTT(int *A, int n, int type) {
//type = 1 DFT
//type = -1 IDFT
change(A, n);
for(int m = 1; m < n; m <<= 1) {
int Wn = Pow(type == 1 ? G : Gi, (P - 1) / (m << 1));
for(int i = 0; i < n; i += 2 * m) {
int w = 1;
for(int j = 0; j < m; j++, w = 1ll * w * Wn % P) {
int x = A[i + j], y = 1ll * w * A[i + j + m] % P;
A[i + j] = (x + y) % P;
A[i + j + m] = (x - y + P) % P;
}
}
}
if(type == -1) {
int inv = Pow(n, P - 2);
for(int i = 0; i < n; i++)
A[i] = 1ll * A[i] * inv % P;
}
}
}
int check(int x) {
for(int i = x; i <= N; i += x)
if(A[i])
return false;
return true;
}
signed main()
{
n = read();
for(int i = 1; i <= n; i++) {
int x = read();
A[x] = 1;
B[N - x] = 1;
}
int lim = 1;
while(lim <= 2 * N) lim <<= 1;
Polynomial :: NTT(A, lim, 1);
Polynomial :: NTT(B, lim, 1);
for(int i = 0; i < lim; i++) A[i] = 1ll * A[i] * B[i] % P;
Polynomial :: NTT(A, lim, -1);
reverse(A, A + 1 + N);
int i = n;
while(1) {
if(check(i)) {
printf("%d\n", i);
return 0;
}
i++;
}
return 0;
}