2021牛客多校第一场H Hash Function
2021牛客多校第一场H Hash Function
题意
\[给定一个有n项的数列a,选定一个最小的seed使得用其构造的hash不会冲突,其中H_{seed}(x)=x\ mod\ seed\\
数据范围1\le n\le 500000,\forall 0\le i< j<n,a_i\neq a_j,0\le a_i \le500000
\]
思路
\[如果两个数a_i,a_j会冲突,当且仅当a_i-a_j\equiv0\ mod\ seed\\
那么题目就转化为了求所有a_i-a_j的因子,并找出不在其中的最小的一个数
\]
\[如果直接暴力求所有的a_i-a_j复杂度O(n^2)会炸\\
但我们注意到a_i的范围只有500000,并且所有的a_i都不相同\\
先考虑这么一个问题,假设我们有两个数组a,b要求所有的a_i+b_j\\
将其每一项都放在多项式的系数上相乘后的多项式的系数分布即为所有的a_i+b_j\\
回到原题,我们取b_i=500000-a_i,那么此时所求的就是所有的500000+a_i-a_j\\
枚举500000后的每一项,去除其所有的质因子,线性扫一遍,遇到的第一个数就是答案\\
多项式乘法复杂度O(nlogn)筛掉所有因子可以做到O(n\sqrt{n})
\]
#include <bits/stdc++.h>
using namespace std;
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int g = 3, a[2000010], inv1[1000010], c[2000010], rev[2000010];
int bj[2000010];
int ksm(int a, int b) {
int res = 1;
while (b) {
if (b & 1)
res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
void ntt(int *a, int n, int f) {
for (int i = 0; i < n; i++)
if (rev[i] < i)
swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1) {
int gn = ksm(g, (mod - 1) / (i << 1));
if (f == -1)
gn = ksm(gn, mod - 2);
for (int j = 0; j < n; j += i << 1) {
int gqn = 1;
for (int k = j; k < i + j; k++) {
int x = a[k], y = 1ll * gqn * a[k + i] % mod;
a[k] = 1ll * (x + y) % mod;
a[k + i] = 1ll * (x - y + mod) % mod;
gqn = gqn * 1ll * gn % mod;
}
}
}
if (f == -1) {
int ny = ksm(n, mod - 2);
for (int i = 0; i < n; i++)
a[i] = a[i] * 1ll * ny % mod;
}
}
void inv(int *b, int *e, int n) {
static int d[1000010];
e[0] = ksm(b[0], mod - 2);
int l = n;
for (n = 2; n = min(n, l); n <<= 1) {
int bit, len = 2;
for (bit = 1; (1 << bit) < (n << 1); bit++)
len <<= 1;
for (int i = 0; i < n; i++)
d[i] = b[i];
for (int i = n; i < len; i++) {
d[i] = 0;
e[i] = 0;
}
for (int i = 0; i < len; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
ntt(e, len, 1);
ntt(d, len, 1);
for (int i = 0; i < len; i++)
e[i] = (2ll - 1ll * d[i] * e[i] % mod + mod) % mod * 1ll * e[i] % mod;
ntt(e, len, -1);
for (int i = n; i < len; i++)
e[i] = 0;
if (n == l)
break;
}
}
void qioudao(int *a, int n) {
for (int i = 0; i < n; i++)
a[i] = 1ll * a[i + 1] * (i + 1) % mod;
}
void jifen(int *a, int n) {
for (int i = n; i > 0; i--)
a[i] = 1ll * a[i - 1] * inv1[i] % mod;
a[0] = 0;
}
void nttln(int *a, int n) {
static int l1[1000010];
static int l2[1000010];
static int e[1000010];
for (int i = 0; i < n; i++)
l1[i] = a[i];
for (int i = 0; i < n; i++)
l2[i] = a[i];
qioudao(l1, n);
inv(l2, e, n);
int bit, len = 2;
for (bit = 1; (1 << bit) < (n << 1); bit++)
len <<= 1;
for (int i = 0; i < n; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
for (int i = n; i < len; i++)
l1[i] = 0;
for (int i = n; i < len; i++)
e[i] = 0;
ntt(l1, len, 1);
ntt(e, len, 1);
for (int i = 0; i < len; i++)
a[i] = 1ll * l1[i] * e[i] % mod;
ntt(a, len, -1);
jifen(a, n);
}
void exp(int *b, int *ee, int n) {
static int gg[1000010];
if (n == 1) {
ee[0] = 1;
return;
}
exp(b, ee, (n + 1) >> 1);
for (int i = 0; i < n; i++)
gg[i] = ee[i];
nttln(gg, n);
int bit, len = 2;
for (bit = 1; (1 << bit) < (n << 1); bit++)
len <<= 1;
for (int i = 0; i < len; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
for (int i = 0; i < n; i++)
gg[i] = (b[i] - gg[i] + mod) % mod;
for (int i = n; i < len; i++)
gg[i] = 0;
for (int i = n; i < len; i++)
ee[i] = 0;
gg[0]++;
ntt(ee, len, 1);
ntt(gg, len, 1);
for (int i = 0; i < len; i++)
ee[i] = 1ll * ee[i] * gg[i] % mod;
ntt(ee, len, -1);
for (int i = n; i < len; i++)
ee[i] = 0;
}
void kksm(int *a, int k, int n) {
nttln(a, n);
for (int i = 0; i < n; i++)
a[i] = 1ll * a[i] * k % mod;
exp(a, c, n);
}
int main() {
inv1[0] = 1;
inv1[1] = 1;
for (int i = 2; i <= 300000; i++)
inv1[i] = (mod - mod / i) * 1ll * inv1[mod % i] % mod;
int n;
scanf("%d", &n);int l;
for(int i=0;i<n;i++)
{
scanf("%d", &l);
a[l]++;
c[500000-l]++;
}
int bit, len = 2;
for(bit=1;(1<<bit)<1000000;bit++)len<<=1;
for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
ntt(a,len,1);ntt(c,len,1);
for(int i=0;i<len;i++)a[i]=1ll*a[i]*c[i]%mod;
ntt(a,len,-1);
for(int i=1000000;i>=500001;i--)
{
if(a[i]!=0)
if(a[i]&&!bj[i-500000])
{
// cout<<i<<"\n";
for(int j=1;j*j<=i-500000;j++)
if((i-500000)%j==0)
{
bj[j]=1;
bj[(i-500000)/j]=1;
}
}
}
for(int i=n;i<=500001;i++)
{
if(!bj[i])
{
cout<<i<<"\n";
break;
}
}
return 0;
}