洛谷P3868 [TJOI2009]猜数字

题目描述:

现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示。

其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。

题解:

中国剩余定理模板。

这道题其实就是求n-ai≡0(mod bi)。

根据同余式变换法则,

如果有a≡b(mod m), 则a+c≡b+c(mod m)成立。

所以这道题就变成了求:n≡ai(mod bi),就是——中国剩余定理的模板。

要用快速乘。

但个人比较喜欢写excrt,因为excrt应用范围更广,而且复杂度和crt一样。

不会扩展中国剩余定理模板请移步:

https://www.cnblogs.com/jiangminghong/p/9857305.html

附上代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int k;
long long ai[20],bi[20];
long long mul(long long x,long long y,long long mod)
{
    long long ans=0;
    while(y>0)
    {
        if(y&1)
            ans=(ans+x)%mod;
        x=(x+x)%mod;
        y>>=1;
    }
    return ans;
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long cnt=exgcd(b,a%b,x,y);
    long long idx=x;
    x=y;
    y=idx-a/b*y;
    return cnt;
}
long long excrt()
{
    long long x=0,y=0;
    long long M=bi[1],ans=ai[1];
    for(int i=2;i<=k;i++)
    {
        long long a=M,b=bi[i],c=((ai[i]-ans)%b+b)%b;
        long long gcd=exgcd(a,b,x,y),idx=b/gcd;
        if(c%gcd!=0)
            return -1;
        x=mul(x,c/gcd,idx);
        ans+=x*M;
        M*=idx;
        ans=(ans%M+M)%M;
    }
    return (ans%M+M)%M;
}
int main()
{
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
        scanf("%lld",&ai[i]);
    for(int i=1;i<=k;i++)
        scanf("%lld",&bi[i]);
    printf("%lld",excrt());
}
原文地址:https://www.cnblogs.com/jiangminghong/p/9857406.html