• 【中国剩余定理-入门】-C++


    中国剩余定理也称孙子定理,是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。

    这玩意在luogu居然有模板题:
    [TJOI2009]猜数字

    先来看一个问题:

    在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”
    

    熟悉吗小学数学学过吗
    这样的问题是基本的中国剩余定理的运用,解题过程有三步:

    1. 找出三个数:从(3)(5)的公倍数中找出被(7)除余(1)的最小数(15),从(3)(7)的公倍数中找出被(5)除余(1)的最小数(21),最后从(5)(7)的公倍数中找出除(3)(1)的最小数(70)
    2. (15)乘以(2)(2)为最终结果除以(7)的余数),用(21)乘以(3)(3)为最终结果除以(5)的余数),同理,用(70)乘以(2)(2)为最终结果除以(3)的余数),然后把三个乘积相加(15∗2+21∗3+70∗2)得到和(233)
    3. (233)除以(3,5,7)三个数的最小公倍数(105),得到余数(23),即(233%105=23)。这个余数23就是符合条件的最小数。

    不得不佩服古人的智慧

    然后看回题目(链接在开头)

    [egin{cases} (n-a_1)|b_1\ (n-a_2)|b_2\ ...\ (n-a_k)|b_k end{cases}\ ]

    变形成同余方程组之后:

    [egin{cases} (n-a_1≡0)pmod {b_1}\ (n-a_2≡0)pmod {b_2}\ ...\ (n-a_k≡0)pmod {b_k}\ end{cases} ]

    很明显的,
    如果(a≡bpmod{m}),则(a+c≡b+cpmod{m})成立。
    这个不难理解,稍微理解一下就可以了。
    然后把上面同余方程组变形一下:

    [ egin{cases}\ nequiv a_1(mod b_1)quad \ nequiv a_2(mod b_2)quad \ ...quad \ nequiv a_k(mod b_k)quad \ end{cases}\ ]

    然后到这里就是中国剩余定理的裸题了。但是需要注意的是因为题目问题,我们需要对每一个(a_i)作这样的操作:
    ( a[i]=(a[i]mod b[i]+b[i])modb[i]; )

    然后还需要注意的就是,这道题目因为数据良(bian)心(tai),所以还需要用快速乘来防止爆long long的情况。
    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll a[110],b[110];
    ll k;
    inline int read()
    {
       int x=0,f=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){
           if(ch=='-')
               f=-1;
           ch=getchar();
       }
       while(ch>='0'&&ch<='9'){
           x=(x<<1)+(x<<3)+(ch^48);
           ch=getchar();
       }
       return x*f;
    }
    inline ll qmul(ll a, ll b, ll m)
    {
        ll res=0;
        while(b>0)
    	{
            if(b&1)res=(res+a)%m;
            a=(a+a)%m;
            b>>=1;
        }
        return res;
    }
    inline void exgcd(ll a,ll b,ll &x,ll &y)
    {
    	if(b==0)
    	{
    		x=1,y=0;
    		return;
    	}
    	exgcd(b,a%b,x,y);
    	int tmp=x;
    	x=y,y=tmp-a/b*y;
    	return;
    }
    ll China()
    {
    	ll ans=0,lcm=1;
    	for(ll i=1;i<=k;i++)
    		lcm*=b[i];
    	ll x,y;
        for(ll i=1;i<=k;i++)
        {
            ll p=lcm/b[i];
            exgcd(p,b[i],x,y);
            x=(x%b[i]+b[i])%b[i];
            ans=(ans+qmul(qmul(p,x,lcm),a[i],lcm))%lcm;
        }
        return (ans+lcm)%lcm;
    }
    int main()
    {
    	cin>>k;
    	for(int i=1;i<=k;i++)
    		a[i]=read();
    	for(int i=1;i<=k;i++)
    		b[i]=read(),a[i]=(a[i]%b[i]+b[i])%b[i];
    	cout<<China();
    	return 0;
    }
    

    ov.

    个人博客地址: www.moyujiang.com 或 moyujiang.top
  • 相关阅读:
    Path Sum 解答
    Binary Tree Paths 解答
    Populating Next Right Pointers in Each Node 解答
    Validate Binary Search Tree 解答
    First Missing Positive
    78 Subsets
    47.Permutations 1&2
    N-Queens 1&2
    Combination Sum_DFS
    38.Count and Say
  • 原文地址:https://www.cnblogs.com/moyujiang/p/11242062.html
Copyright © 2020-2023  润新知