zoukankan      html  css  js  c++  java
  • 【学习笔记】中国剩余定理

    声明:本博客所有随笔都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。

    前言

    找了一些博客,好像都是直接给你结论然后再分析,顺序让我有点难接受,打算按自己的思路理一遍

    这篇博客写的好棒!!

    ————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

    一、概念

    给定 (n) 组非负整数 (a_i), (b_i),求解关于 (x) 的方程组的最小非负整数解。

    [egin{cases}xequiv b_1(mod a_1)\xequiv b_2(mod a_2)\...\xequiv b_n(mod a_n)end{cases} ]

    保证 (b_i)(b_j) 互质

    ————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

    二、分析

    方程有点多,我们先从一个方程解起

    对于方程 (x_iequiv b_i(mod a_i)) ,很显然 (x_i = a_i + b_i * k ( k in Z ))

    那么对于 (n) 个方程就有 (n)(x),我们想想能否将它们合并?

    例如,对于 (s = x_i + x_j),我们想要 (s) 仍然满足 (sequiv b_i(mod a_i))(sequiv b_j(mod a_j))

    显然,(( x_i + k * b_i ) \% b_i = a_i),所以只要 (x_j)(b_i) 的倍数即可,同样,(x_i) 也得为 (b_j) 的倍数

    把它推广一下,即当 (s = x_1 + x_2 + x_3 + ... + x_n) 时,为满足 (s \% b_i = a_i),则 (x_1,x_2...x_{i-1},x_{i+1}...x_n) 得为 (b_i) 的倍数

    整理一下可得,所有的 (x_i) 得为 (b_j ( j eq i )) 的倍数,同时 (x_i \% b_i = a_i)

    还有一个小技巧就是,找 (x_i) 的时候可以先找 (prodlimits_{j eq i}a_j)(b_i) 下的逆元(这里要用扩展欧几里得),再乘以 (a_i)

    ————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

    三、结论

    转载自文章开头的博客

    ————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

    四、(Code)

    代码为P1495 【模板】中国剩余定理(CRT)/曹冲养猪

    #include<bits/stdc++.h>
    #define F(i, x, y) for(int i = x; i <= y; ++ i)
    #define ll long long
    using namespace std;
    ll read();
    const int N = 15;
    int n;
    ll a[N], b[N];
    ll mod = 1, ans, x, y;
    int exgcd(ll a, ll b, ll &x, ll &y)
    {
    	if(b == 0)
    	{
    		x = 1, y = 0; 
    		return a;
    	}
    	int r = exgcd(b, a % b, x, y), tmp = y;
    	y = x - a / b * y, x = tmp;
    	return r;
    }
    int main()
    {
    	n = read();
    	F(i, 1, n) b[i] = read(), a[i] = read(), mod *= b[i];
    	F(i, 1, n) 
    	{
    		exgcd(mod / b[i], b[i], x, y);
    		ans = ((ans + a[i] * x * (mod / b[i])) % mod + mod) % mod;
    	}
    	printf("%lld
    ", ans % mod);
    } 
    ll read()
    {
    	ll x = 0; 
    	char c = getchar();
    	while(c < '0' || c > '9') c = getchar();
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x;
    }
    
  • 相关阅读:
    Linux文件结构
    磁盘分区
    BASH简介
    磁盘的基本概念
    Linux文件操作
    创建文件系统
    文件系统挂载
    一些常用命令
    asp.net创建PPT
    asp.net创建、删除、移动文件夹 文件
  • 原文地址:https://www.cnblogs.com/Bn_ff/p/12716103.html
Copyright © 2011-2022 走看看