zoukankan      html  css  js  c++  java
  • [洛谷P4777] [模板] 扩展中国剩余定理

    扩展中国剩余定理,EXCRT。

    题目传送门

    重温一下中国剩余定理。

    中国剩余定理常被用来解线性同余方程组:

    x≡a[1] (mod m[1])

    x≡a[2] (mod m[2])

    ......

    x≡a[n] (mod m[n])

    但是中国剩余定理只能解决m[1]、m[2]......m[n]两两互质的情况。

    对于m[1]、m[2]......m[n]不两两互质的情况,我们需要用其它的方法解决。

    假设我们已经处理到了第i个方程,设ans为前i-1个方程的解,ms为m[1]*m[2]*...*m[i-1]。

    那么前i-1个方程组的通解为ans+t*ms(t为任意值)。

    而这些解不是都满足第i个方程。

    所以我们需要求出一个k,使ans+k*ms≡a[i](mod m[i])。

    设c=a[i]-ans,原同余方程转换为不定方程:k*ms+kk*m[i]=c(kk不重要)。

    使用exgcd求解即可。

    由不定方程的性质,如果(a[i]-ans)不能被gcd(ms,m[i])整除,则无解。

    若有解,令c/=gcd(ms,m[i]),m[i]/=gcd(ms,m[i])。

    k=k*c(注意要mod m[i])求出k的最小非负解(这道题需要快速乘防爆long long)。

    最后更新一下:ans=ans+k*ms,ms=ms*m[i],并让ans取模新的ms得到最小解。

    对于初值:ans=a[1](显然满足第一个方程),ms=m[1]。

    然后从第二个方程开始算就好了。

     1 #include<cstdio>
     2 #define ll long long
     3 
     4 int n;
     5 ll a[100005],m[100005];
     6 ll ms,ans;
     7 
     8 ll exgcd(ll ea,ll eb,ll &x,ll &y)
     9 {
    10     if(!eb)
    11     {
    12         x=1,y=0;
    13         return ea;
    14     }
    15     ll ret=exgcd(eb,ea%eb,y,x);
    16     y-=ea/eb*x;
    17     return ret;
    18 }
    19 
    20 ll mul(ll x,ll y,ll mod)
    21 {
    22     ll ret=0;
    23     while(y)
    24     {
    25         if(y&1)ret=(ret+x)%mod;
    26         x=(x+x)%mod;
    27         y>>=1;
    28     }
    29     return ret;
    30 }
    31 
    32 int main()
    33 {
    34     scanf("%d",&n);
    35     for(int i=1;i<=n;i++)scanf("%lld%lld",&m[i],&a[i]);
    36     ans=a[1],ms=m[1];
    37     for(int i=2;i<=n;i++)
    38     {
    39         ll k,kk;
    40         ll c=((a[i]-ans)%m[i]+m[i])%m[i];
    41         ll g=exgcd(ms,m[i],k,kk);
    42         //if(c%g)return 0;
    43         m[i]/=g,c/=g;
    44         k=mul(k,c,m[i]);
    45         ans=ans+k*ms;
    46         ms*=m[i];
    47         ans=(ans%ms+ms)%ms;
    48     }
    49     printf("%lld",ans);
    50     return 0;
    51 }
  • 相关阅读:
    c++ socket发送数据时,sendData = char * string 导致的乱码问题
    c++ sprintf() 用法
    c++ 将float 类型转换成string 类型
    c++中 string类型 转为 char []类型
    c++ 去掉所有空格及换行符
    c++处理字符串string.find()与string::npos
    C1010 unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source
    C++ socket bind() 函数绑定错误
    windows 全局安装 composer
    VMware Tools (ubuntu系统)安装详细过程与使用
  • 原文地址:https://www.cnblogs.com/eternhope/p/9726466.html
Copyright © 2011-2022 走看看