当前位置:网站首页>扩展中国剩余定理
扩展中国剩余定理
2022-08-10 20:54:00 【aWty_】
exCRT
CRT
关于 C R T CRT CRT,主要的思想是这样的,对于一个方程组:
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 1 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_1 \pmod {m_2} \\ \vdots \\ x \equiv a_n \pmod {m_n} \end{cases} ⎩⎨⎧x≡a1(modm1)x≡a1(modm2)⋮x≡an(modmn)
来说我们令:
m = ∏ i = 1 n m i , M i = m m i m = \prod_{i = 1}^n m_i, M_i = \frac m {m_i} m=i=1∏nmi,Mi=mim
然后求出 M i M_i Mi 在模 m i m_i mi 意义下的乘法逆元 t i t_i ti,于是我们就得到了答案:
a n s = ∑ i = 1 n a i M i t i ans = \sum_{i = 1}^n a_i M_i t_i ans=i=1∑naiMiti
在这里的计算步骤中,显然在计算逆元的时候要求 gcd ( M i , m i ) = 1 \gcd(M_i, m_i) = 1 gcd(Mi,mi)=1,那么也就是要求 { m i } \{ m_i \} { mi} l两两互质。
exCRT
总体思路
扩展中国剩余定理就是要解决 m i m_i mi 两两不互质的情况时解方程的方法。
但是我们稍微经过一些思考就能发现,要想在 C R T CRT CRT 的基础上小改一下来实现 e x C R T exCRT exCRT 时不可能的,因为如果 gcd ( M i , m i ) ≠ 1 \gcd(M_i, m_i) \neq 1 gcd(Mi,mi)=1 的话那么连逆元都不存在了,所以我们需要跳出 C R T CRT CRT 的框架来思考怎样进行扩展。
我们考虑合并两个方程,如果可以做到很快的合并,那么我们只需要一直合并下去再直接求解剩下的,唯一一个的,简单的,显然的,线性同余方程就能解决问题了。
合并
考虑两个方程的合并:
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \end{cases} { x≡a1(modm1)x≡a2(modm2)
那么根据同余的性质我们就能得到:
x = k 1 m 1 + a 1 = k 2 m 2 + a 2 x = k_1m_1 + a_1 = k_2 m_2 + a_2 x=k1m1+a1=k2m2+a2
移一下项:
k 1 m 1 − k 2 m 2 = a 2 − a 1 k_1m_1 - k_2m_2 = a_2 - a_1 k1m1−k2m2=a2−a1
这个式子的形式可能没有那么直观,所以我们令 a = m 1 , b = m 2 , c = a 2 − a 1 , x = k 1 , y = − k 2 a = m_1, b = m_2, c = a_2 - a_1, x = k_1, y = -k_2 a=m1,b=m2,c=a2−a1,x=k1,y=−k2,这个式子是不是就瞬间变成了这样:
a x + b y = c ax + by = c ax+by=c
这就是一个经典的不定方程求解的问题了,那么根据裴蜀定理,我们就能知道:
- 如果 gcd ( m 1 , m 2 ) ∣ ( r 2 − r 1 ) \gcd(m_1, m_2) \mid (r_2 - r_1) gcd(m1,m2)∣(r2−r1),那么方程可以直接用 e x g c d exgcd exgcd 求出她的一组特殊解
- 否则,方程无解
那么我们求出 x = k 1 m 1 + a 1 x = k_1m_1 + a_1 x=k1m1+a1 之后就得到了一个 x x x 的特殊解同时满足这两个方程。我们给这个特殊解一个新的变量名 X X X。
于是我们就可以愉快的构造新的方程了:
x ≡ X ( m o d l c m ( m 1 , m 2 ) ) x \equiv X \pmod {lcm(m_1, m_2)} x≡X(modlcm(m1,m2))
这个构造应该是非常显然的,因为 x x x 与 X X X 模 m 1 m_1 m1 同余且 x x x 与 X X X 模 m 2 m_2 m2 同余,那么 x x x 与 X X X 模 l c m ( m 1 , m 2 ) lcm(m_1, m_2) lcm(m1,m2) 同余。
算法流程总结
- 在所有方程中取两个出来
- 合并(如果不能合并输出无解)
- 只剩下一个方程直接解这唯一的一个方程得到答案
完结撒花!!!
代码
#include<bits/stdc++.h>
using namespace std;
#define int __int128
#define in read()
#define MAXN 100100
inline int read(){
int x = 0; char c = getchar();
while(c < '0' or c > '9') c = getchar();
while('0' <= c and c <= '9'){
x = x * 10 + c - '0'; c = getchar();
}
return x;
}
void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int n = 0;
int a[MAXN] = {
0 };
int m[MAXN] = {
0 };
int k1 = 0, k2 = 0;
int exgcd(int a, int b, int &x, int &y){
if(!b) {
x = 1, y = 0; return a; }
int d = exgcd(b, a % b, x, y);
int z = x; x = y, y = z - y * (a / b);
return d;
}
signed main(){
n = in; int ans = 0, lcm = 0;
for(int i = 1; i <= n; i++) m[i] = in, a[i] = in;
for(int i = 1; i < n; i++){
k1 = 0, k2 = 0;
int d = exgcd(m[i], m[i + 1], k1, k2);
if((a[i + 1] - a[i]) % d != 0) {
puts("-1"); return 0; }
lcm = m[i] / d * m[i + 1];
a[i + 1] = k1 * (a[i + 1] - a[i]) / d * m[i] + a[i];
a[i + 1] = (a[i + 1] % lcm + lcm) % lcm; m[i + 1] = lcm;
}
int y = 0;
exgcd(1, m[n], ans, y);
write((ans * a[n] + m[n]) % m[n]);
return 0;
}
边栏推荐
猜你喜欢
随机推荐
参天生长大模型:昇腾AI如何强壮模型开发与创新之根?
SELECT:简单的查询操作语法&使用例——《mysql 从入门到内卷再到入土》
shell小技巧(一百三十五)打包指定目录下所用文件,每个文件单独打包
Mark!画出漂亮的神经网络图!神经网络可视化工具集锦搜集
HGAME 2022 Week2 writeup by pankas
优雅退出在Golang中的实现
详叙c中的分支与循环
带你一文读懂SaaS版多租户商城系统对多品牌企业的应用价值
图数据库(Neo4j)入门
化学制品制造业数智化供应链管理系统:建立端到端供应链采购一体化平台
apr_thread使用内存之谜
Redis Command Manual
第四届红帽杯网络安全大赛
Common functions of Auto.js to find pictures and colors
金鱼哥RHCA回忆录:CL210OpenStack操作的故障排除--章节实验
【golang map】 深入了解map内部存储协议
ansible各个模块的详解和使用
我的世界整合包 云服务器搭建方法(ECS)
《mysql 从入门到内卷再到入土》——Mysql基础 学习笔记目录
Rider调试ASP.NET Core时报thread not gc-safe的解决方法