zoukankan      html  css  js  c++  java
  • poj2891 Strange Way to Express Integers poj1006 Biorhythms 同余方程组

    怎样求同余方程组?如:

    [egin{cases} x equiv a_1 pmod {m_1} \ x equiv a_2 pmod {m_2} \ cdots \ x equiv a_n pmod {m_n} end{cases}]

    不保证 (m) 两两互素?
    两两合并!
    比方说

    [egin{cases} x equiv a_1 pmod {m_1} \ x equiv a_2 pmod {m_2} \ end{cases}]

    就是

    [egin{cases} x = m_1x_1+a_1\ x = m_2x_2+a_2\ end{cases}]

    可以变形成

    [m_1x_1+m_2(-x_2)=a_2-a_1 ]

    拿扩欧搞掉这个方程。我们肯定想让 (x) 最小,那就让 (x_1) 最小,这样就求出了 (x) 的特解 (x')
    显然, (x) 的通解是 (x=x'+[m_1,m_2] imes t ,t in mathbb{Z})
    这也就很像是

    [x equiv x' pmod {[m_1,m_2]} ]

    我们惊喜地发现两个方程变成了一个方程。一路做下去就好了。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    int n;
    ll a, r, m, aa, rr, x, y;
    bool flag;
    ll exgcd(ll a, ll b, ll &x, ll &y){
    	if(!b){
    		x = 1;
    		y = 0;
    		return a;
    	}
    	ll re=exgcd(b, a%b, x, y);
    	ll z=x;
    	x = y;
    	y = z - a / b * y;
    	return re;
    }
    int main(){
    	while(scanf("%d", &n)!=EOF){
    		flag = true;
    		n--;
    		scanf("%lld %lld", &aa, &rr);
    		while(n--){
    			scanf("%lld %lld", &a, &r);
    			if(!flag)	continue;
    			ll gcd=exgcd(aa, a, x, y);
    			if((r-rr)%gcd)	flag = false;
    			else
    				x = (((r-rr)/gcd*x)%(a/gcd)+a/gcd)%(a/gcd);
    			x = rr + x * aa;
    			rr = x;
    			aa = a/gcd*aa;
    		}
    		if(flag)	printf("%lld
    ", x);
    		else	printf("-1
    ");
    	}
    	return 0;
    }
    

    如果保证两两互素呢?那就中国剩余定理了。记 (m =prod_{i=1}^n m_i)(M_i=m/m_i)(t_i)(M_i) 在模 (m_i) 意义下的乘法逆元,则一个特解是 (sum_{i=1}^n a_iM_it_i)。通解是 (sum_{i=1}^n a_iM_it_i + mk, k in mathbb{Z})
    证明:因为当 (i ot =j)时,(m_j|M_i),则 (a_iM_it_i equiv 0 pmod {m_j}),而 (a_jM_jt_j equiv a_j pmod {m_j}),证毕。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int a[15], cnt, mul, ans, x, y, dd;
    const int m[]={0, 23, 28, 33};
    int exgcd(int aa, int bb, int &x, int &y){
    	if(!bb){
    		x = 1;
    		y = 0;
    		return aa;
    	}
    	int re=exgcd(bb, aa%bb, x, y);
    	int z=x;
    	x = y;
    	y = z - aa / bb * y;
    	return re;
    }
    int ni(int aa, int bb){
    	int gcd=exgcd(aa, bb, x, y);
    	return (x%bb+bb)%bb;
    }
    int main(){
    	while(scanf("%d %d %d %d", &a[1], &a[2], &a[3], &dd)!=EOF){
    		mul = 1;
    		if(a[1]<0)	break;
    		ans = 0;
    		for(int i=1; i<=3; i++)
    			a[i] %= m[i], mul *= m[i];
    		for(int i=1; i<=3; i++)
    			ans += a[i] * (mul/m[i])%mul * ni(mul/m[i], m[i])%mul;
    		ans -= dd;
    		ans = (ans%mul+mul)%mul;
    		if(!ans)	ans += mul;
    		printf("Case %d: the next triple peak occurs in %d days.
    ", ++cnt, ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    cookie与session的区别
    基于TCP协议的网络编程
    springboot第一篇:springboot基础
    java中的正则表达式
    NIO
    io基础(字节流、字符流、转换流、缓冲字符流)
    基于UDP协议的网络编程
    es6.3学习笔记
    线程同步和线程通信
    java字符串各种编码
  • 原文地址:https://www.cnblogs.com/poorpool/p/8509942.html
Copyright © 2011-2022 走看看