2021牛客暑期多校训练营1

时间:2021-08-11
本文章向大家介绍2021牛客暑期多校训练营1,主要包括2021牛客暑期多校训练营1使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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;
}

原文地址:https://www.cnblogs.com/stler/p/15128551.html