1. 程式人生 > 其它 >2021牛客多校

2021牛客多校

Hash Function

題意

給一個數列長度為\(n\)的數列\(a\),找一個最小的\(seed\),使得數列\(a\)中所有數模\(seed\)後的值全都不一樣。

題解

若數字\(x\)\(y\)\(seed\)後的值一樣,假設\(x>y\),那麼必定存在整數\(k\),使得\(y-x=k\times seed\)

所以,我們要找的那個\(seed\),不能是任何兩個數的差值的因數,於是我們就需要預處理出任意兩個數之間的差值的絕對值,樸素演算法是\(n^2\)的,必定會超時,於是考慮\(FFT\)\(NTT\)

眾所周知,離散域上的卷積的定義為

\[c_i=\sum_{j=0}^na_j \times b_{i-j} \]

其中向量\(c\)

是向量\(a\)和向量\(b\)的卷積。

如何用卷積處理差值呢?在這裡我們是\(a_j\)\(b_{i-j}\)乘,那麼如果設\(a_i=1\)表示\(i\)這個差值存在,\(b_i\)同理,他們他倆相乘的結果不就表示他們下標對應的差值存在麼?C++沒有負下標,於是我們令\(b\)的下標從 \(5e^5\)開始即可,最後處理時,和\(5e^5\)取個差的絕對值就好了。

最後求值的時候用埃氏篩篩一下就行了。

AC程式碼

#include <bits/stdc++.h>

// #define IO ios::sync_with_stdio(NULL)
#define sc(z) scanf("%d", &(z))
#define _ff(i, a, b) for (ll i = a; i <= b; ++i)
#define _rr(i, a, b) for (ll i = b; i >= a; --i)
#define _f(i, a, b) for (ll i = a; i < b; ++i)
#define _r(i, a, b) for (ll i = b - 1; i >= a; --i)
#define mkp make_pair
#define endl "\n"
#define lowbit(x) x&(-x)
#define pb push_back

using namespace std;
typedef double db;
typedef long long ll;
typedef long double ld;

const int N = 2e6 + 5;
const int M = 1e6 + 5;
const ll mod = 1e9 + 7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int maxn = 500000;

struct Complext {
    db a, b;
    Complext(){}
    Complext(db r, db i):a(r),b(i){}
}a[N], b[N];

Complext operator + (Complext a, Complext b) { return Complext(a.a + b.a, a.b + b.b); }
Complext operator - (Complext a, Complext b) { return Complext(a.a - b.a, a.b - b.b); }
Complext operator * (Complext a, Complext b) { return Complext(a.a * b.a - a.b * b.b, a.a * b.b + a.b * b.a); }

int mp[M];
int lim = 1, len, rev[N];

void fft(Complext c[], db flag) {
    //int cnt = 0;
    _f(i, 0, lim) if (i < rev[i]) swap(c[i], c[rev[i]]);
    _f(i, 0, len) {
        int m = 1<<i;
        Complext wn = Complext(cos(pi / m), flag * sin(pi / m));
        for (int j = 0; j < lim; j += (m<<1)) {
            Complext w = Complext(1, 0);
            for (int k = 0; k < m; k++, w = w * wn) {
                Complext u = c[j + k], t = w * c[m + j + k];
                c[j + k] = u + t;
                c[m + k + j] = u - t;
                //cnt++;
            }
        }
    }
    if (flag == -1) _ff(i, 0, lim) a[i].a /= lim;
}

int main() {
    // IO;
    #ifndef ONLINE_JUDGE
    freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    #endif // !ONLINE_JUDGE

    int n, x; cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> x;
        a[x].a = 1;
        b[maxn - x].a = 1;
    }
    // while (lim <= maxn + maxn) lim <<= 1, len++;
    lim = 1<<20, len = 20;
    _f(i, 0, lim) rev[i] = (rev[i>>1]>>1)|((i&1)<<(len-1));
    fft(a, 1); fft(b, 1);
    _f(i, 0, lim) a[i] = a[i] * b[i];
    fft(a, -1);

    _f(i, 0, lim) {
        int tmp = (int)(a[i].a + 0.5);
        if (tmp > 0) mp[abs(i - maxn)] = 1;
    }

   // _ff(i, 1, 10) cout<<mp[i]<<" ";cout<<endl;

    _ff(i, n, maxn+1) {
        int flag = 1;
        for (int j = i; j <= maxn+1; j += i) {
            if (mp[j]) {
                flag = 0;
                break;
            }
        }
        if (flag) {
            cout << i << endl;
            break;
        }
    }

    return 0;
}