中国剩余定理 个人理解

问题

        一个小例子,一个数x 符合以下条件(x mod 3 = 2 ,x mod 5 = 3, x mod 7 =2)求这个数的最小值。

解决方法(除数互质的时候)

看了许多的题解分析,主要的思路如下:

1、问题分解:设 x= x1 + x2 + x3 :(x = 2 (mod 3)的意思为 x mod 3 后的结果为 2)

  • x1 满足(= 2 (mod 3),= 0 (mod 5),= 0 (mod 7 ) )
  • x2 满足(= 0 (mod 3),= 3 (mod 5),= 0 (mod 7 ) )
  • x3 满足(= 0 (mod 3),= 0 (mod 5),= 2 (mod 7 ) )

        如此设置后的结果一定是满足 x 的要求的。

2、继续拆分:x1 = 2 * y1、 x2  = 3 * y2 、 x3 = 2 * y3。

  • y1 (=1 mod 3,=0(mod 5),=0(mod 7)) 
  • y2 (=0 mod 3,=1(mod 5),=0(mod 7))
  • y3 (=0 mod 3,=0(mod 5),=1(mod 7))

我们在求余数为一时比较方便应该是

3、此时 x =  2 * y1+ 3 * y2 + 2 * y3。

如何求 yi?记三个除数(3,5,7)的最小公倍数为 n 。一下两种方案

  1. 对于y1 可知它是 5与7 的公倍数。我们y1从35缓慢增加,每次增加35,判断是否满足y1 mod 3 = 1。满足则找到y1。其他的同理。
  2. 对于y1 我们有以下要求满足的条件 i * y1 - j * 3 = 1(有的写的是i * y1 + j * 3 =1 原因是j 可能取负号)。其余的同理。

此类问题代码解决方案(除数互质时)

a = [3,5,7] ##a 为除数
m = [2,3,2] ##m 为余数

n = 1
for i in a:   ## n为最小公倍数
    n *= i
ans = 0

for i in range(3):
    k = 0   # k % a[i] 需要等于1
    while True:
        k += n//a[i]    ## k每次增加的值为 最小公倍数n除开a[i]的值
        if k % a[i] == 1:
            break
    ans += m[i] * k   ## 要求的值为其余m[i],就用k 乘上m[i]即可。结果加上ans
    ans %= n  ## ans 存放各第二类分割情况的结果的和,求最小,就模上n
print(ans)

如果时除数互质的情况,还是很好解决的。

下面我们来看除数,不互质的情况。

2022年蓝桥杯省赛python B组  B题。题目如下。

 看到题目的第一眼,我其实感觉昂,就这就这,我直接一个一个暴力找总是能找出来的吧。结果确实我暴力跑了三十多分钟还是没有跑出来.....

        通过剩余定理,我们首先要确定的是其除数互质,但是在这里面的数是不互质的。成倍数关系的数我们能知道,取最小的值即可。(比如上述除数为2 时余数为1,除数为4时余数也为1。他们表达虽然差不多,但是更大的数-余数中的信息包含的更多。)

        我们先找2~49中的质数。

        (71条消息) 素数筛 python_我们一起摆烂鸭的博客-CSDN博客_python 素数筛

可知结果为【 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 】

由题目可知 a = [ i for i in range(2,50)]

 m =

[1, 2, 1, 4, 5, 4, 1, 2, 9, 0, 5, 10, 11, 14, 9, 0, 11, 18, 9, 11, 11, 15, 17, 9, 23, 20, 25, 16, 29, 27, 25, 11,17, 4, 29, 22, 37, 23, 9, 1, 11, 11, 33, 29, 15, 5, 41, 46]

a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
m = [1, 2, 1, 4, 5, 4, 1, 2, 9, 0, 5, 10, 11, 14, 9, 0, 11, 18, 9, 11, 11, 15, 17, 9, 23, 20, 25, 16, 29, 27, 25, 11,
     17, 4, 29, 22, 37, 23, 9, 1, 11, 11, 33, 29, 15, 5, 41, 46]

nm = []
for i in a:
    nm.append(m[i - 2])
print(nm)

n = 1
for i in a:  ## n为最小公倍数
    n *= i
ans = 0
print(n)

for i in range(len(a)):
    k = 0  # k % a[i] 需要等于1
    while True:
        k += n // a[i]  ## k每次增加的值为 最小公倍数n除开a[i]的值
        if k % a[i] == 1:
            break
    ans += nm[i] * k  ## 要求的值为其余m[i],就用k 乘上m[i]即可。结果加上ans
    ans %= n  ## ans 存放各第二类分割情况的结果的和,求最小,就模上n
print(ans)

for i in range(2, 50):
    if ans % i != m[i - 2]:
        print(i, m[i - 2])

其运行的结果如下:

哈哈哈,答案没错。又多了一个猜题的技巧了:遇见不会的就填日期了hhhh。

扩展:

        看到最后就有一些聪明的好兄弟要说了:“啊,为什么就要这样互质呢?我直接全部放进去不还是可以?”。enmmm有点道理。我们举个例子 a = 【2,3,10】m =【1,2,9】,啊很简单呀,直接口算我们就知道答案是 29 。但是如果是直接莽用剩余定理呢?我们就会发现 30 就是 2 的倍数,所以就不可能找到一个30 的倍数使其除 2 == 1。所以呢?一定要互质!性质一好吧!这时又会好兄弟要说:“啊,我去掉了9,为什么答案算的11呢?这不对呀,你是不是在框我?”    嗯这时就要看我之前说的,大的数-余数中包含的信息更多。可是为什么在本题中我用小数也求出了正确的答案了呢?因为题目给的是从2 ~ 49 连续的数。其中任意一个和数都能是其中某些质数的积。而其几个小的乘数-余数 的信息能组合为大数- 余数的信息。就相当于无损去除。而本例子中的10 没有 其他的数相乘能得到他,所以将其去除时就丢失了一些信息。

        本例: a = [ 2, 3 ,10 ]  m = [ 1,2 ,9] 其答案是29 .我们反推其因子。10 //2 == 5。29%5 =4。我们用5- 4 来代替 10 - 9。即 a = 【2,3,5】,m = 【1,2,4】用中国剩余定理,结果就是29。

        所以我们能知道 在连续的除数中我们直接保留质数即可,但是要是除数不连续(某些除数不能被其他除数相乘得到)那我们就要保留大的除数了。性质二好吧!

言后:

        一定要养成随手保存的好习惯呀,QAQ,我就是这个扩展这里有点小问题,就习惯性的按了下ctrl + z 结果后面的都没了。刚才细后言时,鼠标又把那两个字的位置滑错了,差点又按了ctrl+z,还好忍住了。言后就言后吧,就不改了。。。。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值