牛客多校第一次反思(H题)
先记录H题,其他待填坑
本质该题等价于给出n个不同的数,O(nlogn)地求出两两之差(取绝对值)。
则可以用fft卷积。
我们记第一个多项式为
\(a_0\) + \(a_1\)\(x\) + \(a_2\)\(x^2\) + ... + \(a_n\)\(x^n\)
其中,如果i在原序列出现过,则\(a_i\) = 1,否则\(a_i\) = 0
我们记第二个多项式为
\(b_0\) + \(b_1\)\(x^{-1}\) + \(b_2\)\(x^{-2}\) + ... + \(b_n\)\(x^{-n}\)
其中,如果i在原序列出现过,则\(b^{-i}\) = 1,否则\(b^{-i}\) = 0
我们发现,如果n, m出现在原序列中(假设n > m)
则上述两个多项式的卷积中 \(x^{n - m}\)的系数必定为1。故如果某个数不是原序列的差,则卷出来对应指数的系数必定为0
而指数不能为负数,则我们给整体加个偏移量(一般为数的上限,这里我们设为500000)
在统计答案i时,取abs(i - 500000)就好。
AC代码:
#include <iostream>
#include <complex>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 2e6 + 10;
//这里为fft板子,一般来说MAXN根据题目而定
const double Pi = acos(-1.0);
typedef complex<double> CP;
CP a[MAXN], b[MAXN];
int limit = 1;
void FFT(CP *x, int inv) {
int bit = 1, m;
CP stand, now, temp;
while((1 << bit) < limit) bit++;
for (int i = 0; i < limit; i++) {
m = 0;
for (int j = 0; j < bit; j++)
if(i & (1 << j)) m |= (1 << (bit - j - 1));
if(i < m) swap(x[m], x[i]);
}
for (int len = 2; len <= limit; len <<= 1) {
m = len >> 1;
stand = CP(cos(2 * Pi / len), inv * sin(2 * Pi / len));
for (CP *p = x; p != x + limit; p += len) {
now = CP(1, 0);
for (int i = 0; i < m; i++, now *= stand) {
temp = now * p[i + m];
p[i + m] = p[i] - temp;
p[i] = p[i] + temp;
}
}
}
if(inv == -1)
for (int i = 0; i < limit; i++)
x[i].real(x[i].real() / limit);
}
//板子结尾
int n;
int tmp;
int vis[MAXN];
int maxn = -1;
int flag;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> tmp;
maxn = max(maxn, tmp);
a[tmp].real(1);
b[500000 - tmp].real(1); //负数的偏移量
}
while (limit <= n + 500000) limit <<= 1;
FFT(a, 1);
FFT(b, 1);
for (int i = 0; i < limit; i++) a[i] = a[i] * b[i];
FFT(a, -1);
for (int i = 0; i <= limit; i++) {
if ((int)float(a[i].real() + 0.5) > 0) {
vis[abs(i - 500000)] = 1; //统计出现过时要减去偏移量取绝对值
}
}
for (int i = n; i <= maxn + 1; i++) {
flag = 1;
for (int j = i; j <= 500000; j += i) {
if (vis[j]) {
flag = 0;
break;
}
}
if (flag) {
cout << i << "\n";
return 0;
}
}
return 0;
}