题意
给你 n n n个数,让你找出一个最小的数字 m m m,使得上述 n n n个数 % m \%m %m后值各不相同。
分析
上述问题等价于:对所有的 i i i和 j j j, ∣ a i − a j ∣ % m ≠ 0 |a_i-a_j|\%m \neq 0 ∣ai−aj∣%m=0,即可求出 ∣ a i − a j ∣ |a_i-a_j| ∣ai−aj∣的所有可能取值,再进行检测。
A
=
{
a
1
,
a
2
.
.
.
a
n
}
,
B
=
{
b
1
,
b
2
.
.
.
b
n
}
A=\{a_1,a_2...a_n\},B=\{b_1,b_2...b_n\}
A={a1,a2...an},B={b1,b2...bn}如何快速求出
A
+
B
A+B
A+B的集合
C
C
C ??
将表达方式进行转换,将相加变成相乘(指数相加)。
A
(
x
)
=
x
a
1
+
x
a
2
+
.
.
.
+
x
a
n
A(x)=x^{a_1}+x^{a_2}+...+x^{a_n}
A(x)=xa1+xa2+...+xan,
B
(
x
)
=
x
b
1
+
x
b
2
+
.
.
.
+
x
b
m
B(x)=x^{b_1}+x^{b_2}+...+x^{b_m}
B(x)=xb1+xb2+...+xbm,使用
F
F
T
FFT
FFT,在
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的时间复杂度内进行求解。
如果是减法,相当于加负数,可以将当前值均加上一个偏移量 d e l t a delta delta,在进行计算,代码中直接取 N N N作为偏移量。
如何检测?
枚举当前数的倍数即可,使用数组标记。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const double PI = acos(-1);
const int N = 5e5 + 10, M = N * 2;
const int delta = 500001;
const int maxn = 1<<20;
#define endl '\n'
#define x first
#define y second
int n;
int rev[maxn], bit, tot;
struct Complex{
double x, y;
Complex operator+ (const Complex& t) const { return {x + t.x, y + t.y}; }
Complex operator- (const Complex& t) const{ return {x - t.x, y - t.y}; }
Complex operator* (const Complex& t) const{ return {x * t.x - y * t.y, x * t.y + y * t.x}; }
}a[maxn], b[maxn];
void fft(Complex a[], int inv){
for(int i = 0; i < tot; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int mid = 1; mid < tot; mid <<= 1){
Complex w1 = Complex({cos(PI/mid), inv * sin(PI/mid)});
for(int i = 0; i < tot; i += mid * 2){
Complex wk = Complex({1, 0});
for(int j = 0; j < mid; j ++, wk = wk * w1){
Complex x = a[i + j], y = wk * a[i + j + mid];
a[i + j] = x + y, a[i + j + mid] = x - y;
}
}
}
}
// 这些数%m的结果互不相同
// 任何两个数相减%seed != 0
// |ai - aj| % seed != 0
// 快速求出所有的|ai - aj|
int vis[N];
bool check(int x){
for(int i = x; i <= N; i += x){
if(vis[i]) return 0;
}
return 1;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n;
for(int i = 1; i <= n; i++) {
int y; cin>>y;
a[y].x = 1;
b[N - y].x = 1;
}
while((1 << bit) < 2 * N + 1) bit++;
tot = 1 << bit;
for(int i = 0; i < tot; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
fft(a, 1), fft(b, 1);
for(int i = 0; i < tot; i++) a[i] = a[i] * b[i];
fft(a, -1);
for(int i = 0; i < (N << 1) - 10; i++){
int now = (int)(a[i].x/tot+0.5);
if(now > 0) vis[(int)abs(i-N)] = 1;
}
for(int i = n; i < delta + 1; i++){
if(check(i)) {
cout<<i<<endl;
return 0;
}
}
return 0;
}