• 中国剩余定理模板+理解 推导


    此处省略引经据典。

    (为了方便叙述,x=(a1,a2,a3)(b1,b2,b3)表示  x≡a1(mod b1)  x≡a2(mod b2) x≡a3(mod b3) )

    举个栗子。

    栗子 求x=(2,3,2)(3,5,7)的最小正整数解。

    考虑转化为三个子问题。

    (显然,对于互质的u,v,可以得到x=(0,0)(u,v)=u*v。因此,(1,0,0)(3,5,7)=(1,0)(3,5*7)=35*(35-1(mod 3))%3)

    思考后可得 x=(2*(1,0,0)(3,5,7)+3*(0,1,0)(3,5,7)+2*(0,0,1)(3,5,7))(mod 3*5*7)

    推而广之,考虑n个两两互质的数 m1,m2,m3,……mn-1,mn,设他们的积为M。

    则,x=(a1,a2,a3,……an)(m1,m2,m3,……mn)=(a1*(1,0,……,0)+a2*(0,1,0,……,0)+……an*(0……0,1))=

    (a1*(M/m1)*((M/m1)-1(mod m1)%m1)+……an*(M/mn)*((M/mn)-1(mod mn)%mn))

    而关于逆元,可以用扩展欧几里得来求(扩展欧几里得求逆元可以参考小蒟蒻的这篇博客,貌似快速幂求逆元也适用?)。

    细节见代码。

     1 #include <cstdio>
     2 using namespace std;
     3 int x,y,M=1;
     4 void exgcd(int aa,int bb,int &x,int &y){
     5     if(bb==0){
     6         x=1;
     7         y=0;
     8         return ;
     9     }
    10     exgcd(bb,aa%bb,y,x);
    11     y-=x*(aa/bb); 
    12 } 
    13 const int sz=1e5+5;
    14 int a[sz],m[sz],ans,n;
    15 int main(){
    16     scanf("%d",&n);
    17     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    18     for(int i=1;i<=n;i++)scanf("%d",&m[i]),M*=m[i];
    19     for(int i=1;i<=n;i++){
    20         exgcd(M/m[i],m[i],x,y);
    21         x=(x%m[i]+m[i])%m[i];
    22         ans+=a[i]*x*(M/m[i]);
    23         ans=(ans%M+M)%M;
    24     }
    25     printf("%d",ans); 
    26     return 0;
    27 }

    引用一个POJ的模板题 POJ1006

    该题代码如下

     1 #include <cstdio>
     2 using namespace std;
     3 int x,y;
     4 const int M=21252;
     5 void exgcd(int aa,int bb,int &x,int &y){
     6     if(bb==0){
     7         x=1;
     8         y=0;
     9         return ;
    10     }
    11     exgcd(bb,aa%bb,y,x);
    12     y-=x*(aa/bb); 
    13 } 
    14 int t,a[3],m[3]={23,28,33},d,ans;
    15 int main(){
    16     for(t=1;;++t){
    17         ans=0;
    18         for(int i=0;i<3;i++){
    19             scanf("%d",&a[i]);
    20             exgcd(M/m[i],m[i],x,y);
    21             x=(x%m[i]+m[i])%m[i];
    22             ans+=a[i]*x*(M/m[i]);
    23             ans=(ans%M+M)%M;
    24         }
    25         scanf("%d",&d);
    26         if(d==-1)break;
    27         ans-=d;
    28         ans=(ans%M+M)%M;
    29         if(ans==0)ans=M;
    30         printf("Case %d: the next triple peak occurs in %d days.
    ",t,ans); 
    31     }
    32     return 0;
    33 }
  • 相关阅读:
    Linux安全应用之防垃圾邮件服务器的构建
    Postfix邮件系统安装配置视频
    Linux常用的安全工具
    Linux系统安全加固(一)
    全球开源软件发展趋势分析
    安装配置FreeBSD9全过程体验
    P1441-砝码称重
    POJ-2376 Cleaning Shifts
    P1514-引水入城
    P1378-油滴扩展
  • 原文地址:https://www.cnblogs.com/BLeaves/p/8651995.html
Copyright © 2020-2023  润新知