[TJOI2009]猜数字(中国剩余定理)

洛咕

题意:有两组数字,每组k个,第一组中的数字分别为a1,a2,...,ak,第二组中的数字分别为b1,b2,...,bk.其中第二组中的数字两两互素.求最小的非负整数n,满足对于任意的i,n-ai能被bi整除.

分析:看懂题目之后,就是裸的中国剩余定理.

n-ai能被bi整除,即\(n-a_i≡0(\mod b_i)\),移项得\(n≡a_i(\mod b_i)\),然后有k个这样的方程构成方程组,且bi两两互质.裸题证毕.

几个细节:ai可能为负数,稍微处理一下.然后出题人很毒瘤,最后相乘的时候会爆long long,所以要用快速乘(会快速幂就会快速乘).

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline LL read(){
    LL s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
LL k,M=1,ans;
LL a[11],b[11];
LL quickmul(LL a,LL b,LL mod){
    LL ans=0;
    while(b){
        if(b&1)ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}//快速乘:快速幂的乘号变加号
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){x=1;y=0;return a;}
    LL d=exgcd(b,a%b,y,x);
    y-=x*(a/b);
    return d;
}
void Intchina(){
    LL Mi,x,y;
    for(int i=1;i<=k;++i){
        Mi=M/b[i];
        exgcd(Mi,b[i],x,y);
        x=(x%b[i]+b[i])%b[i];
        ans=(ans+quickmul(quickmul(Mi,x,M),a[i],M))%M;
    }
    printf("%lld\n",(ans+M)%M);
}
int main(){
    k=read();
    for(int i=1;i<=k;i++){
		a[i]=read();
    }
    for(int i=1;i<=k;i++){
		b[i]=read();M*=b[i];
		while(a[i]<0)a[i]+=b[i];//处理一下ai
    }
    Intchina();
    return 0;
}

posted on 2019-03-09 17:09  PPXppx  阅读(148)  评论(0编辑  收藏  举报