2021牛客多校第一场H

题意:给你 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值