• 中国剩余定理


    中国剩余定理:


    类似于韩信点兵的问题。

    求出方程 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;
    }
    

      



  • 相关阅读:
    Apache 2.4+php 5.4 安装
    Linux 进程状态
    解决Redhat Linux AS使用yum时出现This system is not registered with RHN的问题(改用CentOS的yum)
    nagios 事件处理
    awk调用shell命令的两种方法:system与print
    磁盘性能分析
    如何通过JQuery将DIV的滚动条滚动到指定的位置
    GCC Windows Linux 下编译学习1
    Linux命令
    GCC Windows Linux 下编译学习2
  • 原文地址:https://www.cnblogs.com/Przz/p/5409653.html
Copyright © 2020-2023  润新知