题意:
给出一个包含
N
N
N个正整数的集合
S
S
S,求一个最小的
P
P
P 使
S
i
%
P
S_i\ \% P
Si %P得到
N
N
N个不同的结果(即不产生哈希冲突)
题解:
∵
a
%
P
!
=
b
%
P
\ \because a\%P!=b\%P
∵a%P!=b%P
∴
a
b
s
(
a
−
b
)
%
P
!
=
0
\therefore abs(a-b)\%P!=0
∴abs(a−b)%P!=0
∴
∀
a
,
b
∈
S
,
a
b
s
(
a
−
b
)
%
P
!
=
0
\therefore \forall a,b\in S,abs(a-b)\%P!=0
∴∀a,b∈S,abs(a−b)%P!=0
所以只要枚举
P
P
P ,判断
k
∗
P
(
k
∈
Z
+
)
k*P (k\in Z^+)
k∗P(k∈Z+)是否是
S
i
−
S
j
S_i-S_j
Si−Sj的差值,但是如果枚举
i
,
j
i,j
i,j求差值时间是
O
(
n
2
)
O(n^2)
O(n2)。不难推出
a
−
b
=
(
500000
−
b
)
+
a
−
500000
a-b=(500000-b)+a-500000
a−b=(500000−b)+a−500000,令
A
i
=
[
i
∈
S
]
,
B
i
=
[
500000
−
i
∈
S
]
A_i=[i\in S],B_{i}=[500000-i\in S]
Ai=[i∈S],Bi=[500000−i∈S],用 NTT求一下
A
A
A和
B
B
B的卷积就好了(具体为什么可以自己推一下),时间是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 998244353;
using namespace std;
inline int read(){
char c=getchar();int x=0,s=1;
while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*s;
}
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 5e6+10;
const int maxn = 1e3+10;
int c[N],a[N],b[N];
int limit=1,L,rev[N],G=3,Gi=332748118;
void NTT(int *A,int type){//NTT加速
for(int i=0;i<limit;i++) if(i<rev[i])swap(A[i],A[rev[i]]);
for(int mid=1;mid<limit;mid<<=1){
int Wn=qpow(type==1?G:Gi , (mod-1)/(mid<<1));
for(int j=0;j<limit;j+=(mid<<1)){
int w=1;
for(int k=0;k<mid;k++,w=(w*Wn)%mod){
int x=A[j+k],y=(w*A[j+mid+k])%mod;
A[j+k]=(x+y)%mod;
A[j+mid+k]=(x-y+mod)%mod;
}
}
}
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n; cin>>n;
for(int i=1;i<=n;i++){
cin>>c[i];
a[c[i]]++;
b[500000-c[i]]++;
}
while(limit<=1000000)limit<<=1,L++;
for(int i=0;i<limit;i++)rev[i]=(rev[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);
int inv=qpow(limit,mod-2);
for(int i=0;i<=1000000;i++)a[i]=(a[i]*inv)%mod;
for(int i=1;i<=500005;i++){
int flag=0;
for(int j=i+500000;j<=1000000;j+=i)flag|=a[j];
/*
因为A[i][j]B卷积是i+j=i+(500000-x ),有一半<=500000,一半>=500000,
但是<=500000的部分是反着的,所以取>=500000的一半就好了
*/
if(!flag){
cout<<i<<endl; break;
}
}
}