2021牛客暑期多校训练营1 题解

423 阅读1分钟

H

思路

很容易想到如果aimodxajmodxa_i\mod x\neq a_j\mod x,那么xabs(aiaj)x\nmid abs(a_i-a_j)。因此如果我们求出abs(aiaj)abs(a_i-a_j)的集合CC,就可以将问题转化为找最小的一个数,使得它和它的倍数没有在CC中出现过。

朴素做法求CCO(N2)O(N^2)的,考虑如何优化。

构造一个多项式A=p0+p1x+p2x2++pnxnA=p_0+p_1x+p_2x^2+\cdots+p_nx^n,如果iiaa中出现过,就把xix^i的系数设为11,否则设为00。再构造一个多项式B=q0+q1x+q2x2++qnxnB=q_0+q_1x+q_2x^2+\cdots+q_nx^n,如果500000i500000-iaa中出现过,就把xix^i的系数设为11,反之同理。

两个多项式相乘,就可以得到新的多项式C=k0+k1x+k2x2++k2nx2nC=k_0+k_1x+k_2x^2+\cdots+k_{2n}x^{2n},根据A,BA,B的定义可以发现如果CCxix^i的系数不为00,这一项必然是由AA中系数不为00的项与BB中系数不为00的项相乘得到,代表i=au+500000avi=a_u+500000-a_v存在。因此i5000000\left|i-5000000\right|就是刚开始要求的CC集合。

多项式相乘的过程用快速傅里叶变换优化,复杂度为O(NlogN)O(N\log N)

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
const int N=1<<21,M=5E5+1,P=998244353,G=3,Gi=332748118;
ll n,m,lim=1<<20,len=20,x;
ll inv[N],a[N],b[N],vis[N];
ll ksm(ll x,ll y)
{
	ll ret=1;
	while(y)
	{
		if(y&1)
			ret=(ret*x)%P;
		x=(x*x)%P;
		y>>=1;
	}
	return ret;
}
ll check(ll x)
{
	for(int i=x;i<=M;i+=x)
	{
		if(vis[i])
			return 0;
	}
	return 1;
}
void ntt(ll *c,ll ty)
{
	rep(i,0,lim-1)
		if(i<inv[i])
			swap(c[i],c[inv[i]]);
	for(ll m=2;m<=lim;m<<=1)
	{
		ll wn=ksm(ty==1?G:Gi,(P-1)/m);
		for(int k=0;k<lim;k+=m)
		{
			ll w=1;
			ll cel=m>>1;
			rep(j,0,cel-1)
			{
				ll t=w*c[k+j+cel]%P;
				ll u=c[k+j];
				c[k+j]=(u+t)%P;
				c[k+j+cel]=(u-t+P)%P;
				w=(w*wn)%P;
			}
		}
	}
}
void print()
{
	rep(i,1,lim)
	{
		if(a[i])
		{
			op(i,a[i],a[4]);
			en;
		}
	}
}
int main()
{
	read(n);
	rep(i,1,n)
	{
		read(x);
		a[x]=1;
		b[M-x]=1;
	}
	rep(i,0,lim-1)
		inv[i]=(inv[i>>1]>>1) | ((i&1)<<(len-1));
	ntt(a,1);
	ntt(b,1);
	rep(i,0,lim)
		a[i]=a[i]*b[i];
	ntt(a,-1);
	ll inv_=ksm(lim,P-2);
	rep(i,0,lim)
	{
		ll tmp=a[i]*inv_%P;
		if(tmp>0)
			vis[abs(i-M)]=1;
	}
	rep(ans,n,M)
	{
		if(check(ans))
		{
			OP(ans);
			break;
		}
	}
}