2021牛客暑期多校训练营1
2021牛客暑期多校训练营1_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
H - Hash Function
给定一个长度为\(n\)的数组\(a\),每个元素互不相同,请你求出最小的\(p\),使得每个元素对\(p\)取模后互不相同。
可以发现,如果要满足题目所给条件,那么对于任意两个元素\(a_i\),\(a_j\),必须不满足\(a_i-a_j\equiv0(mod~p)\)。
我们先考虑如何求出所有的\(a_i+a_j\):
对于每个数\(i\),如果它出现的次数为\(j\),那么我们就让多项式的第\(j\)项系数为\(i\),就是\(i \cdot x^j\)。
比如\(a\)为\(2\),\(3\),\(4\),那么多项式就为\(f(x)=1 \cdot x^4 + 1 \cdot x^3 + 1 \cdot x^2 + 0 \cdot x^1 + 0 \cdot x^0\)。
然后我们对\(f(x)\)和它本身跑一遍\(NTT\)就会得到:
\(g(x)=1 \cdot x^ 8 + 2 \cdot x^7 + 3 \cdot x^6 + 2 \cdot x^5 + 1 \cdot x^4 + 0 \cdot x^3 + 0 \cdot x^2 + 0 \cdot x^1 + 0 \cdot x^0\)。
\(i \cdot x^j\)就代表和为\(j\)的对数有\(i\)对。
然后我们考虑如何求\(a_i-a_j\),我们只需要将上述\(a_j\)替换为\(MAXN-a_j(MAXN\geq 5\cdot10^5)\),然后构造新的\(F(x)\)和\(f(x)\)进行\(NTT\)即可,那么求出来的就是\(a_i+MAXN-a_j\)的对数,那么对于\(i \cdot x^j\)我们只需要让\(j-MAXN\),就是差为\(i\)的对数。
然后枚举答案即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace NTT {
const int MAXN = 5e5 + 5;
const int MOD = 998244353;
const int G = 3;
template<typename T>
T fpow(T a, int n) {
T res = 1;
while (n) {
if (n & 1) {
res = (res * a) % MOD;
}
a = (a * a) % MOD;
n >>= 1;
}
return res;
}
int inv(int a) {
return fpow(a, MOD - 2);
}
struct Complex {
double x, y;
Complex(double _x, double _y): x(_x), y(_y) {}
Complex operator +(Complex oth) {
return Complex(x + oth.x, y + oth.y);
}
Complex operator -(Complex oth) {
return Complex(x - oth.x, y - oth.y);
}
Complex operator *(Complex oth) {
return Complex(x * oth.x - y * oth.y, x * oth.y + y * oth.x);
}
};
int R[MAXN << 2], L, limit = 1;
void NTT(int a[], int opt) {
for (int i = 0; i < limit; ++i) {
if (i < R[i]) {
swap(a[i], a[R[i]]);
}
}
for (int mid = 1; mid < limit; mid <<= 1) {
int val = fpow(G, (MOD - 1) / (mid * 2));
if (opt == -1) val = inv(val);
for (int len = mid << 1, pos = 0; pos < limit; pos += len) {
for (int k = 0, w = 1; k < mid; ++k, w = w * val % MOD) {
int x = a[pos + k], y = w * a[pos + mid + k] % MOD;
a[pos + k] = (x + y) % MOD;
a[pos + k + mid] = (x - y + MOD) % MOD;
}
}
}
if (opt == 1) return;
int t = inv(limit);
for (int i = 0; i < limit; ++i) {
a[i] = a[i] * t % MOD;
}
}
void poly(int a[], int b[], int deg) {
while (limit <= deg) {
limit <<= 1, ++L;
}
for (int i = 0; i < limit; ++i) {
R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
}
NTT(a, 1);
NTT(b, 1);
for (int i = 0; i < limit; ++i) {
a[i] = a[i] * b[i] % MOD;
}
NTT(a, -1);
}
}; // namespace NTT
using NTT::poly;
const int MAXN = 5e5 + 5;
bool vis[MAXN];
int a[MAXN << 2], b[MAXN << 2];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
++a[x], ++b[MAXN - x];
}
poly(a, b, MAXN << 1);
// 枚举系数
for (int i = MAXN + 1; i <= MAXN + MAXN; ++i) {
if (a[i]) {
vis[i - MAXN] = true;
}
}
// 枚举答案
// 因为元素最大只有500000, 所以即使每个元素都不同, 答案最大也只有500001
for (int i = 1; i <= 500001; ++i) {
int j;
for (j = i; j <= 500000; j += i) {
// 如果数组中两个数的差值是i的倍数, 则不满足条件直接break
if (vis[j]) {
break;
}
}
if (j > 500000) {
cout << i << '\n';
break;
}
}
system("pause");
return 0;
}

浙公网安备 33010602011771号