中国剩余定理

中国剩余定理

构造法(只适用模数两两互质的情况,CRT的本质思想)

  1. 对于解线性同余方程组 useless,因为完全可以被增量法代替

  2. 但是揭示了若模数两两互质,则线性同余方程组一定有解。

    若模数为合数 q, q=p1e1p2e2p3e3...pkek

    1. xmodq=axmodpiei=a

    2. 若给出一个模数不一定为质数线性方程组,判断是否有解,可将每个模数拆成 素数幂 的形式

      对于底数相同的方程分到一组,可先假设幂最高的成立,这样就很容易检查幂低的是否矛盾,若有矛盾则无解

      因为此时每一组之间的模数都是两两互质的,所以只要组中没有矛盾,则该方程组一定有解

中国剩余定理2 - 题目 - Daimayuan Online Judge

性质 2.2 的应用

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
//[p, [s, a]] 为该组以p为底,p的幂为s, x mod s = a 
map<int, vector<PII> > mp;
bool solve()
{
	int n;
	scanf("%d", &n);
	mp.clear();
	while(n--)
	{
		int a, m;
		scanf("%d%d", &a, &m);
		for (int i = 2; i <= m / i; i++)
		{
			if (m % i)
				continue;
			int s = 1;
			while(m % i == 0)
			{
				s *= i;
				m /= i;
			}
			mp[i].push_back({s, a % s});
		}
		if (m > 1)
			mp[m].push_back({m, a % m});
	}
	for (auto t : mp)
	{
		int p = t.first;
		//找到该组幂最大的
		int now = max_element(mp[p].begin(), mp[p].end())->second;
		for (auto i : mp[p])
		{
			if (now == -1)
				now = i.second;
			if (now % i.first != i.second)
				return false;
		}
	}
	return true;
}
int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		if (solve())
			puts("Yes");
		else
			puts("No");
	}
	return 0;
}

增量法 (适用于模数不一定两两互质的情况)

给定 n 个方程,求 x ,满足 xai(modmi), 且 0<=x<lcm(m1,m2...mn)

可逐一合并两个同余方程,最后剩下的同余方程 xa(modlcm(m1,m2...mn))a 就是答案

合并两个同余方程的过程为:

1.xa(modb)xc(modd)x=bt+a,tbtca(modd)g=exgcd(b,d)gca,2.g=exgcd(b,d)t0bt+ds=gtd=dgt=t0+dy(y)t0,t0<0t0=t0+d3.t0=t0cag,t0bt+ds=cat0btca(modd)t=t0+dy(y)4.x=bt+a=b(t0+dy)+a=bdy+bt0+axbt0+a(modbd)

中国剩余定理 - 题目 - Daimayuan Online Judge

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if (b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	ll xx, yy;
	ll d = exgcd(b, a % b, xx, yy);
	x = yy, y = xx - a / b * yy;
	return d;
}

void merge(ll &a, ll &b, ll c, ll d) // d <= 1e9, b可能很大
{
	// bt = c - a (mod d)
	if (a == -1 && b == -1)
		return;
	ll x, y;
	ll g = exgcd(b, d, x, y);
	if ((c - a) % g != 0)
	{
		a = b = -1;
		return;
	}
	d /= g; // d'
	ll t0 = ((c - a) / g) % d * x % d; // 注意 c - a 可能很大,及时取模
	//t = t0 (mod d')
	if (t0 < 0) t0 += d; // 若为负数则 + 模数 就是最小非负整数
	a = b * t0 + a;
	b = b * d;
}

void solve()
{
	int n;
	scanf("%d", &n);
	ll a = 0, b = 1; //当前的方程为 x mod b = a,每次迭代合并一个 x mod c = d
	for (int i = 1; i <= n; i++)
	{
		ll c, d;
		scanf("%lld%lld", &c, &d);
		merge(a, b, c, d);
	}
	printf("%lld\n", a);
}
int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
		solve();	
	return 0;
}

并且中国剩余定理可以推出:

q=p1e1p2e2p3e3...pkek

$

posted @   hzy0227  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示