码迷,mamicode.com
首页 > 其他好文 > 详细

中国剩余定理

时间:2019-08-16 20:47:37      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:def   ++   case   gcd   通过   ret   scanf   names   min   

中国剩余定理:若各方程的模数两两互质,设
M =
k ∏ i=1
mi,Mi = M mi,MiM′ i ≡ 1 (mod mi) 则同余方程组在模 M 下的解唯一且解为 x≡a1M1M′ 1 +a2M2M′ 2 + ... +akMkM′ k (mod M)

然后我们需要用到扩欧求Mi‘的逆元就好了扩欧(求逆元的数,mod数,x,y)

#include<iostream>
#include<cstdio>
using namespace std;
int d,M=23*28*33,ans,t;
int m[4]={0,23,28,33};//存mod数 
int a[4];
void exgcd(int a,int b,int &d,int &x,int &y)
{
    if(!b)
    {
        x=1;
        y=0;
        d=a;
    }
    else
    {
        exgcd(b,a%b,d,x,y);
        int t=x;
        x=y;
        y=t-a/b*y;
    }
}
int intchina(int n)//中国剩余定理 
{
    ans=0;//注意初始化 
    int Mi,x,y,g;
    for(int i=1;i<=n;i++)
    {
        Mi=M/m[i];
        exgcd(Mi,m[i],g,x,y);
        ans=(ans+Mi*x*a[i])%M;
    }
    if(ans<=d) return 21252-(d-ans);
    else return ans-d;//ans的分类讨论 
}
int main()
{
    while(1)
    {
        t++;
        scanf("%d%d%d%d",&a[1],&a[2],&a[3],&d);
        if(a[1]==-1&&a[2]==-1&&a[3]==-1&&d==-1) break;
        a[1]%=23,a[2]%=28,a[3]%=33;
        ans=intchina(3);
        printf("Case %d: the next triple peak occurs in %d days.\n", t, ans);
    }
}

 

https://www.luogu.org/problemnew/solution/P4777

把两个同余方程 x≡a1 (mod m1),x≡a2 (mod m2)

改写为 x = a1 +pm1,x = a2 +qm2

联立得 pm1 −qm2 = a2 −a1

通过拓展欧几里得算法得到 p,q 的一组解,

x′ = a1 +pm1 为这两个方程的一个解

于是得到新的同余方程 x≡x′ (mod lcm(m1,m2))

 1 //niiick
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstring>
 7 #include<cstdio>
 8 using namespace std;
 9 typedef long long lt;
10 const int maxn=100010;
11 int n;
12 lt ai[maxn],bi[maxn];
13 
14 lt mul(lt a,lt b,lt mod)
15 {
16     lt res=0;
17     while(b>0)
18     {
19         if(b&1) res=(res+a)%mod;
20         a=(a+a)%mod;
21         b>>=1;
22     }
23     return res;
24 }
25 
26 lt exgcd(lt a,lt b,lt &x,lt &y)
27 {
28     if(b==0){x=1;y=0;return a;}
29     lt gcd=exgcd(b,a%b,x,y);
30     lt tp=x;
31     x=y; y=tp-a/b*y;
32     return gcd;
33 }
34 
35 lt excrt()
36 {
37     lt x,y,k;
38     lt M=bi[1],ans=ai[1];
39     for(int i=2;i<=n;i++)
40     {
41         lt a=M,b=bi[i],c=(ai[i]-ans%b+b)%b;
42         lt gcd=exgcd(a,b,x,y),bg=b/gcd;
43         if(c%gcd!=0) return -1;
44         x=mul(x,c/gcd,bg);
45         ans+=x*M;
46         M*=bg;
47         ans=(ans%M+M)%M;
48     }
49     return (ans%M+M)%M;
50 }
51 
52 int main()
53 {
54     cin>>n;
55     for(int i=1;i<=n;++i)
56     cin>>bi[i]>>ai[i];
57     printf("%lld",excrt());
58     return 0;
59 }

 

中国剩余定理

标签:def   ++   case   gcd   通过   ret   scanf   names   min   

原文地址:https://www.cnblogs.com/zjzjzj/p/11366092.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!