2021牛客暑期多校第一场 Hack function

题意

给定 \(n\)个互不相同的数,找一个最小的模域,使得它们在这个模域下互不相同。

\(n\leq 5\times10^5,0\leq a_i\leq 5\times10^5\)

题解

\(a\)与\(b\)模\(n\)同余,当且仅当\(n\mid |a-b|\),所以我们要找出所有互不相同的\(|a_i-a_j|\)。

考虑用NTT计算,记\(m=5\times10^5\),设\(B(x)=\sum_{i=0}^{m}b_ix^i\),其中\(b_i=1\)表示\(i\)在\(a\)中出现过,令\(C(x)=\sum_{i=0}^{m}c_ix^i=\sum_{i=0}^{m}b_{m-i}x^i\),\(D(x)=B(x)C(x)=\sum_{i=0}^{}d_ix^i\),其中

 

\[d_i=\sum_{j=0}^{i}b_jc_{i-j}=\sum_{j=0}^ib_jb_{i-m-j} \]

 

所以\(d_i>0\)表示\(i-m\)是\(a\)中某两个数的差,即存在\(j,k\)使得\(|a_j-a_k|=i-m\)。之后从小到大枚举可能的答案,判断是否存在某个\(|a_i-a_j|\)与其倍数相等即可。总复杂度\(O(n\log n)\)。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=1<<30,N=4e6+10;
const ll M=998244353;
int gt=0,r[N],l;
ll lim,aa[N],bb[N];
ll pm(ll x,ll p){ll res=1;while(p){if(p&1)res=res*x%M;p>>=1;x=x*x%M;}return res;}
void ntt(ll *a,int lim,int typ){
	for(int i=0;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
	for(int mid=1;mid<lim;mid<<=1){
		ll w1=pm(3,(M-1)/(mid<<1));if(typ==-1)w1=pm(w1,M-2);
		for(int R=mid<<1,j=0;j<lim;j+=R){
			ll w=1;
			for(int i=0;i<mid;i++,w=w*w1%M){
				ll x=a[i+j],y=w*a[i+j+mid]%M;
				a[i+j]=(x+y)%M,a[i+j+mid]=(x-y+M)%M;
			}
		}
	}
	if(typ==-1){
		ll inv=pm(lim,M-2);for(int i=0;i<=lim;i++)a[i]=a[i]*inv%M;
	}
}
void mul(ll *a,ll *b,ll lim){
	for(int  i=0;i<=lim;i++)aa[i]=a[i],bb[i]=b[i];
	ntt(aa,lim,1);ntt(bb,lim,1);
	for(int i=0;i<=lim;i++)aa[i]=aa[i]*bb[i]%M;
	ntt(aa,lim,-1);for(int i=0;i<=lim;i++)a[i]=aa[i];
}
int n,c[N],a[N];
void f1(){
	scanf("%d",&n);
	int mx=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		mx=max(mx,a[i]);
		aa[a[i]]=1;
		bb[500000-a[i]]=1;
	}
	int l=0,nn=500000;lim=1;
	while(lim<=nn+nn){++l;lim<<=1;}
	for(int i=0;i<lim;i++){
		r[i]=r[i>>1]>>1|(((i&1)<<(l-1)));
	}
	ntt(aa,lim,1);
	ntt(bb,lim,1);
	for(int i=0;i<lim;i++)aa[i]=aa[i]*bb[i]%M;
	ntt(aa,lim,-1);
	for(int i=0;i<=500000;i++)if(aa[i+500000]>0){
		c[i]=1;
	}
	for(int i=n;i<=mx+1;i++){
		int tag=1;
		for(int j=i;j<=500000;j+=i){
			if(c[j]){tag=0;break;}
		}
		if(tag){
			printf("%d",i);return ;
		} 
	}
}
int main(){
	f1();
	return 0;
}