题目链接:https://ac.nowcoder.com/acm/contest/11166/H
涉及到的东西其实不是很难,但是多项式加速还是比较难想到的。
题目可以转化为:找到最小的mod,使得$a_i$处于mod的不同同余系中。扫一眼同余的性质,有一条:
若,则。
并且,若,则对于p的某一因数,。
根据上面两条,我们要求的就是:最小的、且不为所给的数中任意两个数的差的因数的数。
但是这个多项式加速就比较难想。我们可以这样总结:若需要对于两个数组中的元素、两两之间进行操作,朴素算法需要,可以考虑多项式优化为。
我们可以构造两个多项式:
一个多项式系数为表示数i是否出现在数组中。
另一个多项式系数表示数-i是否出现在数组中。但是,多项式的项数不能为负数呀?那么,考虑给它+5e5,使得意义为5e5-i这个数是否在数组中出现。
两个多项式用FFT/NTT相乘后,卷积的结果即为:第i项表示是否有i+5e5-j这个数存在于这个数组中任选两个数相减后的结果,因此可知,下标小于5e5的部分没有意义。若某一项系数,则说明i-5e5这个数可以差出来。
保险点还是写NTT,FFT涉及取整的问题,容易wa。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e5+100; const int mx=5e5; const int mod=998244353; namespace IO{ template<typename T>void write(T x) { if(x<0) { putchar('-'); x=-x; } if(x>9) { write(x/10); } putchar(x%10+'0'); } template<typename T> void read(T &x) { x = 0;char ch = getchar();int f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+(ch-'0');ch=getchar();}x*=f; } }; namespace Math{ ll w; const int p=::mod; struct complex{ ll real,imag; complex(ll a=0,ll b=0){ real=a; imag=b; } friend complex operator*(const complex&a,const complex&b){ complex ans; ans.real=((a.real*b.real%p+a.imag*b.imag%p*w%p)%p+p)%p; ans.imag=((a.real*b.imag%p+a.imag*b.real%p)%p+p)%p; return ans; } }; ll x1,x2; ll ksm(ll a,ll b,ll p){ ll ans=1; while(b){ if(b&1) ans=(ans*a)%p; a=(a*a)%p; b>>=1; } return ans; } ll ksm(complex a,ll b,ll p){ complex ans(1,0); while(b){ if(b&1) ans=ans*a; a=a*a; b>>=1; } return ans.real%p; } bool Cipolla(ll n,ll&x0,ll&x1){ n%=p; if(ksm(n,(p-1)>>1,p)==p-1) return false; ll a; while(true){ a=rand()%p; w=((a*a%p-n)%p+p)%p; if(ksm(w,(p-1)>>1,p)==p-1) break; } complex x(a,1); x0=(ksm(x,(p+1)>>1,p)+p)%p; x1=(p-x0+p)%p; return true; } }; namespace NTT{ #define mul(x,y) ((1ll*x*y>=mod?x*y%mod:1ll*x*y)) #define dec(x,y) (1ll*x-y<0?1ll*x-y+mod:1ll*x-y) #define add(x,y) (1ll*x+y>=mod?1ll*x+y-mod:1ll*x+y) #define ck(x) (x>=mod?x-mod:x) typedef vector<int> Poly; int ksm(int a,int n,int mod=::mod){ int res=1; while(n){ if(n&1)res=1ll*res*a%mod; a=1ll*a*a%mod; n>>=1; } return res; } const int img=86583718; const int g=3,INV=ksm(g,mod-2); const int mx=21; int R[maxn<<2],deer[2][mx][maxn<<2],inv[maxn<<2]; void init(const int t) { for(int p = 1; p <= t; ++ p) { int buf1 = ksm(g, (mod - 1) / (1 << p)); int buf0 = ksm(INV, (mod - 1) / (1 << p)); deer[0][p][0] = deer[1][p][0] = 1; for(int i = 1; i < (1 << p); ++ i) { deer[0][p][i] = 1ll * deer[0][p][i - 1] * buf0 % mod; deer[1][p][i] = 1ll * deer[1][p][i - 1] * buf1 % mod; } } inv[1] = 1; for(int i = 2; i <= (1 << t); ++ i) inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod; } int NTT_init(int n) { int lim = 1, l = 0; while(lim < n) lim <<= 1, l ++ ; for(int i = 0; i < lim; ++ i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (l - 1)); return lim; } void ntt(Poly &A, int type, int lim) { A.resize(lim); for(int i = 0; i < lim; ++ i) if(i < R[i]) swap(A[i], A[R[i]]); for(int mid = 2, j = 1; mid <= lim; mid <<= 1, ++ j) { int len = mid >> 1; for(int pos = 0; pos < lim; pos += mid) { int *wn = deer[type][j]; for(int i = pos; i < pos + len; ++ i, ++ wn) { int tmp = 1ll * (*wn) * A[i + len] % mod; A[i + len] = ck(A[i] - tmp + mod); A[i] = ck(A[i] + tmp); } } } if(type == 0) { for(int i = 0; i < lim; ++ i) A[i] = 1ll * A[i] * inv[lim] % mod; } } Poly poly_mul(Poly A, Poly B) { int deg = A.size() + B.size() - 1; int limit = NTT_init(deg); Poly C(limit); ntt(A, 1, limit); ntt(B, 1, limit); for(int i = 0; i < limit; ++ i) C[i] = 1ll * A[i] * B[i] % mod; ntt(C, 0, limit); C.resize(deg); return C; } Poly poly_inv(Poly &f, int deg) { if(deg == 1) return Poly(1, ksm(f[0], mod - 2)); Poly A(f.begin(), f.begin() + deg); Poly B = poly_inv(f, (deg + 1) >> 1); int limit = NTT_init(deg << 1); ntt(A, 1, limit), ntt(B, 1, limit); for(int i = 0; i < limit; ++ i) A[i] = B[i] * (2 - 1ll * A[i] * B[i] % mod + mod) % mod; ntt(A, 0, limit); A.resize(deg); return A; } Poly poly_idev(Poly f) { int n = f.size(); for(int i = n - 1; i-1>=0 ; -- i) f[i] = 1ll * f[i - 1] * inv[i] % mod; f[0] = 0; return f; } Poly poly_dev(Poly f) { int n = f.size(); for(int i = 1; i < n; ++ i) f[i - 1] = 1ll * f[i] * i % mod; f.resize(n - 1); return f; } Poly poly_ln(Poly f, int deg) { Poly A = poly_idev(poly_mul(poly_dev(f), poly_inv(f, deg))); return A.resize(deg), A; } Poly poly_exp(Poly &f, int deg) { //cerr<<deg<<endl; if(deg == 1) return Poly(1, 1); Poly B = poly_exp(f, (deg + 1) >> 1); B.resize(deg); Poly lnB = poly_ln(B, deg); for(int i = 0; i < deg; ++ i) lnB[i] = ck(f[i] - lnB[i] + mod); int limit = NTT_init(deg << 1); ntt(B, 1, limit), ntt(lnB, 1, limit); for(int i = 0; i < limit; ++ i) B[i] = 1ll * B[i] * (1 + lnB[i]) % mod; ntt(B, 0, limit); B.resize(deg); return B; } Poly poly_pow(Poly&f,int k){ f=poly_ln(f,f.size()); for(auto&x:f)x=1ll*x*k%mod; return poly_exp(f,f.size()); } Poly power(Poly f,int k1,int k2,int deg){ int s=0; while(f[s]==0&&s<f.size())++s; if(1ll*s*k1>=deg){ return vector<int>(deg); } int Inv=ksm(f[s],mod-2,mod); int Mul=ksm(f[s],k2); deg-=s; for(int i=0;i<deg;++i)f[i]=f[i+s]; f.resize(deg); for(int i=0;i<deg;++i)f[i]=1ll*f[i]*Inv%mod; auto res1=poly_ln(f,deg); for(int i=0;i<res1.size();++i)res1[i]=1ll*res1[i]*k1%mod; auto res2=poly_exp(res1,deg); for(int i=0;i<deg;++i)res2[i]=1ll*res2[i]*Mul%mod; deg+=s; int now=s*k1; Poly res;res.resize(deg); for(int i=deg-1;i>=now;--i)res[i]=res2[i-now]; for(int i=now-1;i>=0;--i)res[i]=0; return res; } Poly Poly_Sqrt(Poly&f,int deg){ if(deg==1)return Poly(1,1); Poly A(f.begin(),f.begin()+deg); Poly B=Poly_Sqrt(f,(deg+1)>>1); Poly IB=poly_inv(B,deg); int lim=NTT_init(deg<<1); ntt(A,1,lim),ntt(IB,1,lim); for(int i=0;i<lim;++i){ A[i]=1ll*A[i]*IB[i]%mod; } ntt(A,0,lim); for(int i=0;i<deg;++i){ A[i]=(1ll*A[i]+B[i])%mod*inv[2]%mod; } A.resize(deg); return A; } Poly Sqrt(Poly&f,int deg){ const int Pow=ksm(2,mod-2); int k1=1; if(f[0]!=1){ k1=ksm(f[0],mod-2); for(int i=1;i<f.size();++i){ f[i]=1ll*k1*f[i]%mod; } ll x0,x1; assert(Math::Cipolla(f[0],x0,x1)); k1=min(x1,x0); f[0]=1; } auto Ln=poly_ln(f,deg); for(int i=0;i<f.size();++i){ Ln[i]=1ll*Ln[i]*Pow%mod; } auto Exp=poly_exp(Ln,deg); for(int i=0;i<Exp.size();++i)Exp[i]=1ll*Exp[i]*k1%mod; return Exp; } Poly poly_sin(Poly&f,int deg){ Poly A(f.begin(),f.begin()+deg); Poly B(deg),C(deg); for(int i=0;i<deg;++i){ A[i]=1ll*A[i]*img%mod; } B=poly_exp(A,deg); C=poly_inv(B,deg); const int inv2i=ksm(img<<1,mod-2); for(int i=0;i<deg;++i){ A[i]=1ll*(1ll*B[i]-C[i]+mod)%mod*inv2i%mod; } return A; } Poly poly_cos(Poly&f,int deg){ Poly A(f.begin(),f.begin()+deg); Poly B(deg),C(deg); for(int i=0;i<deg;++i){ A[i]=1ll*A[i]*img%mod; } B=poly_exp(A,deg); C=poly_inv(B,deg); const int inv2=ksm(2,mod-2); for(int i=0;i<deg;++i){ A[i]=(1ll*B[i]+C[i])%mod*inv2%mod; } return A; } Poly poly_arcsin(Poly f,int deg){ Poly A(f.size()),B(f.size()),C(f.size()); A=poly_dev(f); B=poly_mul(f,f); for(int i=0;i<deg;++i){ B[i]=dec(mod,B[i]); } B[0]=add(B[0],1); C=Poly_Sqrt(B,deg); C=poly_inv(C,deg); C=poly_mul(A,C); C=poly_idev(C); return C; } Poly poly_arctan(Poly f, int deg) { Poly A(f.size()), B(f.size()), C(f.size()); A = poly_dev(f); B = poly_mul(f, f); B[0] = add(B[0], 1); C = poly_inv(B, deg); C = poly_mul(A, C); C = poly_idev(C); C.resize(deg); return C; } }; using NTT::Poly; using namespace IO; int n,t; Poly a,b; bool vis[maxn]; signed main(){ //freopen("in.txt","r",stdin); //clock_t c1 = clock(); NTT::init(NTT::mx-1); //for(auto x:tmp)cerr<<x<<" ";cerr<<endl; a.resize(maxn),b.resize(maxn); int n;read(n); if(n==1){ cout<<1<<endl; return 0; } for(int i=0;i<n;++i){ int x;read(x); a[x]=1; b[mx-x]=1; } auto res=NTT::poly_mul(a,b); for(int i=mx;i<=2*mx;++i){ if(res[i]){ vis[i-mx]=1; //cerr<<i<<endl; } } bool flag=0; for(int i=1;i<=mx+1;++i){ int now=0; for(int j=i;j<=mx;j+=i){ now|=(vis[j]!=0); if(now)break; } if(!now){ cout<<i<<endl; flag=1; break; } } assert(flag); //std::cerr << "Time:" << clock() - c1 << "ms" << std::endl; return 0; }