zoukankan      html  css  js  c++  java
  • 中国剩余定理

    中国剩余定理:


    类似于韩信点兵的问题。

    求出方程 x = a[i](mod m[i]),mi互为素数

    令Mi = m1*m2...*m[i-1]*m[i+1]*....

    那么 gcd(Mi,mi) = 1.    故存在pi,qi使 Mi*pi + mi*qi = 1(扩展欧几里得)


    令ei = Mi*pi

    那么有  ei = 0(mod mj),j != i

           ei = 1(mod mj),j = i

    所以:

    e0*a0 + e1*a1 + ..... + en*an是方程的解,

    在[ 0,m[0]*.....*m[n] )中只有唯一解,取模即可


    poj 1006 模板题 

    大意:

    人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这天,人在对应的方面表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。


    ll CRT(ll a[],ll m[],ll n)
    {
        ll M = 1;
        for(ll i = 0; i < n; i++) M *= m[i];
    
        ll ret = 0;
    
        for(ll i = 0; i < n; i++)
        {
            ll x,y;
            ll tm = M/m[i];
            ex_gcd(tm,m[i],x,y);
            ret = (ret+tm*x*a[i])%M;
        }
        return (ret+M)%M;
    }



    poj 2891

    求解mi不互素的问题,可以模仿中国剩余定理,两两合并

    对于 x mod a0 = r0,可以知道最小值为 a0 + r0

    若同时存在x mod a1 = r1 => (k0*a0 + r0)mod a1 = r1, 

    那么 k1*a1 + r1 = k0*a0 + r0


    于是得到 k0*a0 - k1*a1 = r1 - r0,利用扩展欧几里得可以求出x,公约数t

    (但是前提是 a*m + b*n = gcd(a,b) ), 所以(r1 - r0)%t必需为0,否则不满足公式

    于是我们可以得出k0 = x*(r1-r0)/t , x实际来自( a0*x + a1*y == gcd(a0,a1) )

    所以这个公共的x1 = r0 + k0*x. 于是我们得到一个新的 a = x1  ,  r = x1 % lcm(a0,a1)


    于是我们可以往后面慢慢推了。

    假设有3对数: 8 4   :   7 3   : 12  7

    x = 8*x0 + 4 = 7*x1 + 3   可以求出x为 11,于是把11作为r

    a*t + r = 12*t1 + 7, 于是a要满足能同时除尽7和8,即它们的最小公倍数  /*个人见解

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    const ld eps=1e-10;
    const int inf = 0x3f3f3f;
    const int maxn = 100005;
    
    ll ans,d;
    int flag;
    
    ll ex_gcd(ll a,ll b,ll &x,ll &y)
    {
        ll ret;
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        ret = ex_gcd(b,a%b,x,y);
        ll tmp =x;
        x = y;
        y = tmp-(a/b)*y;
        return ret;
    }
    
    
    ll get(ll m1,ll m2,ll a)
    {
        ll x,y;
        d = ex_gcd(m1,m2,x,y);
        if(a % d != 0)                            //无法满足等式
        {
            flag = 0;
        }
    
        ll t = (x*(a/d)%m2+m2)%m2;               //得出要求的x1
        return t;
    }
    
    int main()
    {
        ll m1,m2,a1,a2;
        ll k;
        while(scanf("%I64d",&k) != EOF)
        {
            flag = 1;
            scanf("%I64d%I64d",&m1,&a1);
            ans = a1;
            for(ll i = 1; i < k; i++)
            {
                scanf("%I64d%I64d",&m2,&a2);
                ll t = get(m1,m2,a2-a1);
                ans += (m1*t);
                m1 = m1*m2/d;                          //获得最小公倍数
                ans = (ans%m1+m1)%m1;
                a1 = ans;
            }
            if(!flag)
                printf("-1
    ");
            else
                printf("%I64d
    ",ans);
        }
        return 0;
    }
    

      

    hdu 1573

    题意:

    给你两组数a[],b[].让你求出≤n的正整数中,有多少个满足 x % a[i] = b[i]

    感觉和上面那个差不多吧,合并后求出最小的值。 然后通过加所有数的最小公倍数得出结果


    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    const ld eps=1e-10;
    const int inf = 0x3f3f3f;
    const int maxn = 100005;
    ll a[15];
    ll b[15];
    ll ans,d;
    int flag;
    
    ll ex_gcd(ll a,ll b,ll &x,ll &y)
    {
        ll ret;
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        ret = ex_gcd(b,a%b,x,y);
        ll tmp =x;
        x = y;
        y = tmp-(a/b)*y;
        return ret;
    }
    
    
    ll get(ll m1,ll m2,ll a)
    {
        ll x,y;
        d = ex_gcd(m1,m2,x,y);
        if(a % d != 0)                            //无法满足等式
        {
            flag = 0;
        }
    
        ll t = (x*(a/d)%m2+m2)%m2;               //得出要求的x1
        return t;
    }
    
    int main()
    {
        ll m1,m2,a1,a2;
        ll  n;
        ll m;
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%I64d%I64d",&n,&m);
            for(int i = 0; i < m; i++)
                scanf("%d",&a[i]);
    
            for(int j = 0; j < m; j++)
                scanf("%d",&b[j]);
    
            flag = 1;
            ans = b[0];
            m1 = a[0],a1 = b[0];
            for(ll i = 1; i < m; i++)
            {
                m2 = a[i],a2 = b[i];
                ll t = get(m1,m2,a2-a1);
                ans += (m1*t);
                m1 = m1*m2/d;                          
                ans = (ans%m1+m1)%m1;
                a1 = ans;
            }
            ll num = 0;
            while(ans <= n)
            {
                if(ans != 0)                          //正整数
                    num ++;
                ans += m1;
            }
            if(!flag)
                printf("0
    ");
            else
                printf("%I64d
    ",num);
        }
        return 0;
    }
    

      



  • 相关阅读:
    LeetCode 189. Rotate Array
    LeetCode 965. Univalued Binary Tree
    LeetCode 111. Minimum Depth of Binary Tree
    LeetCode 104. Maximum Depth of Binary Tree
    Windows下MySQL的安装与配置
    LeetCode 58. Length of Last Word
    LeetCode 41. First Missing Positive
    LeetCode 283. Move Zeroes
    《蚂蚁金服11.11:支付宝和蚂蚁花呗的技术架构及实践》读后感
    删除docker下的镜像
  • 原文地址:https://www.cnblogs.com/Przz/p/5409653.html
Copyright © 2011-2022 走看看