2021牛客暑期多校訓練營1
阿新 • • 發佈:2021-08-11
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\)
然後列舉答案即可。
#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; }