2021牛客暑期多校训练营1 H题Hash Function (FFT/NTT)

在这里插入图片描述
题目大意:
对于给出的n个互不相同的数,寻找最小的一个模数p使得对于任意ai%p都不相同。

解题思路:
根据同余定理可知,若A-B=C且模数为C的约数,则必然会是A%p=B%p。所以只需要统计出N个数的两两差值即可。考虑用FFT/NTT优化达到O(NlogN)。多项式乘法使得幂次相加,只需要令第ai位为1,另一个多项式中第G-ai位为1即可,枚举从G+1开始。

const int N=2097152+3,P=998244353,G=3;
int n,m,invn,invG,f[N],g[N],tr[N];
inline void in(Re &x)
{
    int f=0;
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int mi(Re x,Re k)
{
    Re s=1;
    while(k)
    {
        if(k&1)
            s=(LL)s*x%P;
        x=(LL)x*x%P,k>>=1;
    }
    return s;
}
inline int inv(Re x)
{
    return mi(x,P-2);
}
inline void NTT(Re *f,Re n,Re op)
{
    for(Re i=0; i<n; ++i)
        if(i<tr[i])
            swap(f[i],f[tr[i]]);
    for(Re p=2; p<=n; p<<=1)
    {
        Re len=p>>1,w1=mi(op?invG:G,(P-1)/p);
        for(Re st=0; st<n; st+=p)
            for(Re i=st,base=1; i<=st+len-1; ++i)
            {
                Re tmp=(LL)base*f[len+i]%P;
                f[len+i]=(f[i]-tmp+P)%P,(f[i]+=tmp)%=P,base=(LL)base*w1%P;
            }
    }
}
inline void times(Re *f,Re n,Re *g,Re m)
{
    for(m+=n,n=1; n<=m; n<<=1)
        ;
    invn=inv(n),invG=inv(G);
    for(Re i=1; i<n; ++i)
        tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
    NTT(f,n,0),NTT(g,n,0);
    for(Re i=0; i<n; ++i)
        f[i]=(LL)f[i]*g[i]%P;
    NTT(f,n,1);
    for(Re i=0; i<=m; ++i)
        f[i]=(LL)f[i]*invn%P;
}
const int LC=5e5+10;
ll a[500010];
ll fuck[LC+100];
signed main()
{
    ll op;
    in(op);
    ll rnm=0;
    for(int i=0; i<op; i++)
    {
        in(a[i]);
        rnm=max(rnm,a[i]);
        f[a[i]]=1;
        g[LC-a[i]]=1;
    }
    n=m=LC;
    times(f,n,g,m);
    int tail=n+m+50;
    for(int i=op; i<=tail-LC; i++)
    {
        if(f[i+LC])
        {
            for(int j=1; j*j<=i; j++)
            {
                if(i%j==0)
                {
                    fuck[j]=1;
                    fuck[i/j]=1;
                }
            }

        }
    }
    for(int i=op;; i++)
    {
        if(fuck[i])
            continue;
        printf("%lld",i);
        return 0;
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值