【luogu3868】【TJOI2009】猜数字[模板] [数论 中国剩余定理]

P3868 [TJOI2009]猜数字

是一道中国剩余定理的模版题  

 

中国剩余定理:

求同余方程解x:

m1,m2...mn两两互质 对于任意整数a1,a2...an有且只有一个解:

x=Σki=1 ai*M/mi*ti  (mod m1*m2..*mk) 其中M=m1*m2*...mk,ti为同余方程M/mi*ti≡1(mod mi)的解,即mi的逆元

 所有数据中,第一组数字的绝对值不超过109(可能为负数),第二组数字均为不超过6000的正整数,且第二组里所有数的乘积不超过1018

关于快速乘 来自题解大佬的说法

快速乘就是用来处理在爆long long 的边缘来回试探的乘法下要取模的一种操作

其实应该叫龟速乘

核心思想就是把一个数按二进制拆分,然后一位一位对应乘。

和快速幂差不多

int qmul(int a,int b,int mod)
{
    int ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%mod;
        a=(a+a)%mod;b>>=1;
    }
    return ans;
}

中国剩余定理:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 ll k,a[15],m[15],M;
 5 
 6 template<class t>void rd(t &x)
 7 {
 8     x=0;int w=0;char ch=0;
 9     while(!isdigit(ch)) w|=ch=='-',ch=getchar();
10     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
11     x=w?-x:x;
12 }
13 
14 void exgcd(ll a,ll b,ll &x,ll &y)//扩展欧几里德
15 {
16     if(!b) {x=1,y=0;return;}
17     exgcd(b,a%b,x,y);
18     ll t=x;x=y,y=t-a/b*y;
19 }
20 
21 ll qmul(ll a,ll b,ll mod)
22 {
23     ll ans=0;
24     while(b)
25     {
26         if(b&1) ans=(ans+a)%mod;
27         a=(a+a)%mod;b>>=1;
28     }
29     return ans;
30 }
31 
32 ll china()
33 {
34     ll ans=0,M=1,x,y;
35     for(int i=1;i<=k;++i) M*=m[i];
36     for(int i=1;i<=k;++i)
37     {
38         ll Mi=M/m[i];
39         exgcd(Mi,m[i],x,y);//求同余方程解
40         x=(x%m[i]+m[i])%m[i];
41         ans=(ans+qmul(a[i],qmul(Mi,x,M),M))%M;//快速乘 防止爆long long 
42     }
43     return (ans+M)%M; 
44 }
45 
46 int main()
47 {
48     rd(k);
49     for(int i=1;i<=k;++i) rd(a[i]);
50     for(int i=1;i<=k;++i) rd(m[i]);
51     printf("%lld",china());
52     return 0;
53 }

原文地址:https://www.cnblogs.com/lxyyyy/p/10538333.html