题意:给你 n个数,找出一个数 x(最小且不在这些数之中),让这 n 个数对 x取模互不相等
思路:转换,即使所有数满足|ai-aj|!=0modx,那么我们找出所有|ai-aj|即可
(其实就是求两数之和)
而快速求两数之和看这里:小圆前辈的素数——FFT_yezi_coder的博客-CSDN博客
当然,在这之前:
先学fft:十分简明易懂的FFT(快速傅里叶变换)_路人黑的纸巾-CSDN博客_fft
B站有个视频我觉得讲的不错:快速傅里叶变换(FFT)——有史以来最巧妙的算法?_哔哩哔哩_bilibili
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 5000010;
const double Pi = acos(-1.0);
struct comple
{
double x, y;
comple(double xx=0, double yy=0)
{
x = xx;
y = yy;
}
}a[N],b[N];
comple operator + (comple a, comple b) { return comple(a.x + b.x, a.y + b.y); }
comple operator - (comple a, comple b) { return comple(a.x - b.x, a.y - b.y); }
comple operator * (comple a, comple b) { return comple(a.x*b.x - a.y*b.y, a.x*b.y + b.x*a.y); }
int len = 1;
int l, r[N];
bool vis[N];//放最后结果
void fft(comple* A, int flag)
{
for (int i = 0; i < len; i++)
{
if (i < r[i])
{
swap(A[i], A[r[i]]);
}
}
for (int mid = 1; mid < len; mid <<= 1)
{
comple Wn(cos(Pi / mid), flag * sin(Pi / mid));
for (int now = mid << 1, j = 0; j < len; j += now)
{
comple w(1, 0);
for (int k = 0; k < mid; k++, w = w * Wn)
{
comple x = A[j + k], y = w * A[j + k + mid];
A[j + k] = x + y, A[j + k + mid] = x - y;
}
}
}
}
//求两数之和,就是x^ai次方再用卷积,将有ai的项前面的系数化为1即可
int main()
{
int n;
cin >> n;
int Max = 0;
const int M = 500010;//这是为了下标偏移量,为了将两数之差改为两数之和
for (int i = 0; i < n; i++)
{
int c;
cin >> c;
Max = max(Max, c);//这是为了后面计算,因为答案一定在[n,Max+1]
a[c].x++;//因为ai!=aj,所以可以这样将系数化为1
b[M - c].x++;//这样相当于是求差了,最后得出来的结果再用M减去就行了
}
while (len <= 2 * M)//这是最高次幂!!!!!!!!
{
len <<= 1;
l++;
}
for (int i = 0; i < len; i++)
{
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
}
fft(a, 1), fft(b, 1);
for (int i = 0; i < len; i++)//如果是因为这个,那我要气死了,好,我现在气死了
{
a[i] = a[i] * b[i];
}
fft(a, -1);
for (int i = 0; i < 2 * M; i++)
{
a[i].x = int(a[i].x / len + 0.5);//这里是除以len
if (a[i].x)
{
vis[abs(i - M)] = 1;
}
}
for (int i = n; i <= Max + 1; i++)//判断i可不可以
{
int f = 1;
for (int j = i; j <= Max + 1; j += i)//如果i是因子也不符合条件
{
if (vis[j])
{
f = 0;
break;
}
}
if (f)
{
cout << i << endl;
break;
}
}
return 0;
}