扩展欧几里德、中国剩余定理



前言

听从大佬的,开始刷数论hhhhhh

  1. 扩展欧几里得 与 中国剩余定理
    http://blog.miskcoo.com/2014/09/chinese-remainder-theorem
  2. 中国剩余定理及其实现
    https://blog.csdn.net/u010468553/article/details/38346195
  3. 中国剩余定理
    https://baike.baidu.com/item/%E5%AD%99%E5%AD%90%E5%AE%9A%E7%90%86/2841597?fr=aladdin&fromid=11200132&fromtitle=%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86

青蛙的约会 - POJ - 1061

思路
题目求解的是 (x + km)%L = (y + kn)%L 这一方程中的k,这一方程可以化为 x + km - aL = y + kn - bL,进而化为 k(n - m) + (a - b)L = x - y,也就是扩欧的形式 ax + by = c,将其解除,其中x的位置就是k,也就是答案

	#include<cstdio>
	using namespace std;
	typedef long long ll;

	ll extgcd(ll a, ll b, ll& x, ll& y){
	    ll d = a;
	    if(!b){
	        x = 1, y = 0;
	    }else{
	        d = extgcd(b, a%b, y, x);
	        y -= (a/b) * x;
	    }
	    return d;
	}

	int main(){
	    ll p, q, m, n, l;
	    while(~scanf("%lld%lld%lld%lld%lld", &p, &q, &m, &n, &l)){
	        ll x, y;
	        ll a = n - m;
	        ll b = l;
	        ll c = p - q;
	        ll d = extgcd(a, b, x, y);
	        if(c%d != 0){
	            puts("Impossible");
	        }else{
	            a /= d;
	            b /= d;
	            c /= d;
	            ll ans = (x*c%b + b)%b;
	            printf("%lld\n", ans);
	        }
	    }
	}


The Balance - POJ - 2142

题意
求解ax + n = by 与 ax = n + by中 x + y 最小,ax + by 尽量小的解
思路
这题个人也是一知半解 T^T
首先求得解,再令其分别取得x与y的最小整数解,最后比较两组解x + y的大小,输出答案
原因嘛,其中一部分是因为 |x| + |y| = |x0 + b/d * t | + |y0 - a/d * t|,当t=0时取得最小解,所以取x与y的最小整数解得到两解作比较,但是ax + by尽量小似乎?没用到??

	#include<cstdio>
	using namespace std;
	typedef long long ll;

	inline int mabs(int x){ return x < 0 ? -x : x; }

	int extgcd(int a, int b, int& x, int& y){
		int d = a;
		if(!b){
			x = 1, y = 0;
		}else{
			d = extgcd(b, a%b, y, x);
			y -= (a/b) * x;
		}
		return d;
	}

	int main(){
	    int a, b, c;
	    while(~scanf("%d%d%d", &a, &b, &c) && (a + b + c)){
	    	int x1, y1, x2, y2;
	    	int g = extgcd(a, b, x1, y1);
	    	a /= g;
	    	b /= g;
	    	c /= g;

	    	x2 = ((x1*c)%b + b)%b;
	    	y2 = mabs((c - a*x2)/b);

	    	y1 = ((y1*c)%a + a)%a;
	        x1 = mabs((c - b*y1)/a);

	        if(x1 + y1 < x2 + y2){
	            printf("%d %d\n", x1, y1);
	        }else{
	            printf("%d %d\n", x2, y2);
	        }
	    }
	}


Biorhythms - POJ - 1006

题意
给定a, b, c, d, 求解 x = a(mod 23), x = b(mod 28), x = c(mod 33),的x(x > d),输出 x - d
思路
中国剩余定理裸题(互质)

	#include <iostream>
	#include <cstring>
	#include <cstdio>
	#include <algorithm>
	using namespace std;
	const int N = 3;
	typedef long long ll;

	int m[N] = {23, 28, 33};
	int a[N];
	int m_tot = 23*28*33;

	int extgcd(int a, int b, int& x, int& y){
	    int d = a;
	    if(!b){
	        x = 1, y = 0;
	    }else{
	        d = extgcd(b, a%b, y, x);
	        y -= a/b*x;
	    }
	    return d;
	}

	int res(){
	    int ans = 0;
	    for(int i = 0; i < N; i++){
	        int mt = m_tot/m[i];
	        int t, y;
	        extgcd(mt, m[i], t, y);
	        ans += a[i] * t * mt;
	    }
	    return (ans%m_tot + m_tot)%m_tot;
	}

	int main(){
	    int t;
	    scanf("%d", &t);
	    while(t--){
	        int d = 0, csn = 0;
	        while(scanf("%d%d%d%d", &a[0], &a[1], &a[2], &d) && (~a[0] || ~a[1] || ~a[2] || ~d)){
	            int ans = res();
	            while(ans <= d)     ans += m_tot;
	            printf("Case %d: the next triple peak occurs in %d days.\n", ++csn, ans - d);
	        }
	    }
	}


Strange Way to Express Integers - POJ - 2891

题意
给定k组数,每组数满足 x = ri(mod ai),求最小的x,如无解,输出-1
思路
中国剩余定理裸题(非互质)

	#include <iostream>
	#include <cstring>
	#include <cstdio>
	#include <algorithm>
	#include <sstream>
	#include <iomanip>
	using namespace std;
	typedef long long ll;
	const int N = 1e3 + 15;

	ll a[N], m[N];

	ll extgcd(ll a, ll b, ll& x, ll& y){
	    ll d = a;
	    if(!b){
	        x = 1, y = 0;
	    }else{
	        d = extgcd(b, a%b, y, x);
	        y -= a/b*x;
	    }
	    return d;
	}

	ll crt(ll n){
	    if(n == 1){
	        return (m[0] > a[0] ? a[0] : -1);
	    }else{
	        for(int i = 1; i < n; i++){
	            if(m[i] <= a[i])    return -1;

	            ll x, y;
	            ll d = extgcd(m[0], m[i], x, y);
	            if((a[i] - a[0])%d != 0)    return -1;
	            ll t = m[i]/d;
	            ll k = ((a[i] - a[0])/d*x%t + t)%t;
	            a[0] = m[0] * k + a[0];
	            m[0] = m[0] * m[i]/d;
	            a[0] = (a[0]%m[0] + m[0])%m[0];
	        }
	    }
	    return a[0];
	}

	int main(){
	    ll n;
	    while(~scanf("%lld", &n)){
	        for(int i = 0; i < n; i++){
	            scanf("%lld%lld", &m[i], &a[i]);
	        }
	        printf("%lld\n", crt(n));
	    }
	}