YbtOJ 「数学基础」 第3章 同余问题

同余问题

同余

整除和同余的关系:

  1. ab (mod m) 当且仅当m|(ab)
  2. ab (mod m) 当且仅当a=b+k×m (m为整数)

同余的性质:

  1. 同加性:ab (mod m) 那么 a+cb+c (mod m)

  2. 同乘性:ab (mod m) 那么 acbc (mod m)

    一般情况下 如果ab (mod m)cd (mod m)acbd (mod m)

    但同余不满足同除性

  3. 同幂性:ab (mod m) 那么anbn (mod m)

  4. ax (mod p)ax (mod q) 其中pq互质 则ax (mod pq)

费马小定理

如果p为质数 那么对于任意一个整数a 满足apa (mod p)

推论:当p为质数且p不是a的约数时 ap11 (mod p)

欧拉函数

性质:

  1. n=pk 其中n,k为正整数 p为质数 那么φ(n)=pkpk1
  2. n,m为正整数 且gcd(n,m)=1 那么φ(n)=φ(n)×φ(m)
  3. i=1n(11pi) (pin唯一分解的底数(质数))

欧拉定理:

gcd(a,n)=1时 有aφ(n)1 (mod n)

扩展欧几里得算法

扩欧证明及解法

image

同余方程证明及解法

image

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

A. 【例题1】同余方程

对于ax1 (mod b) 保证一定有解 那么a,b一定互质 所以用扩欧可以求出一组解 但这组解不一定是最小整数解

那么我们x mod b+bmod b即可(因为在模意义下一定有gcd(a,b)个解)

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long 
const int N = 1e8 + 1;
const int mod = 1e9 + 7;

int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}

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

int a , b , x , y;

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	a = read() , b = read();
	exgcd ( a , b , x , y );
	cout << ( x % b + b ) % b << endl;
	return 0;
	
}

B. 【例题2】约数之和

对于一个数n,若n=p1m1p2m2pnmn 。对于pi在和中贡献 j=0mipij 。则约数和为 i=1nj=0mipij

易对于 AB 来说 Ans=i=1nj=0Bmipij

累乘的原因:因为你第一组p1random 和第二组p2random中的每一个数都需都可以组成一个因数 那么使用乘法分配律就可以不重不漏地(因为是质数)求得最终的数量和

等比数列公式:

(1): x=p0+p1pm

(2): px=p1+p2pm+1

(2)(1) 则得 x=piB  m i + 11pi1
Ans=i=1n(piB  m i + 11pi1)

分子可以用快速幂求 分母看是否与9901互质 如果不互质的话就是pi1的逆元 如果互质 那么pi mod 9901=1

不互质时 需要用到一个结论:如果pi mod x=b 那么pt mod x=bt

我们以二次方为例 设p=kx+b 那么p2=k2x2+2kbx+b2

所以在mod x意义下 p2 mod x=b2

所以pirandommod 9901=1

此时分母在模意义下为0 因为这个分数为整数 那么分子在模意义下也为0 那么我们用j=0Bmipij=Bmi+1来计入答案

注意:实现时需要+mod%mod

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long 
const int N = 5e7 + 5;
const int mod = 9901;
int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}
		
int a , b , n , m , c[N] , prime[N] , cnt , ans = 1;
		
int ksm ( int x , int k )
{
	int base = x , res = 1;
	while (k) 
	{
		if ( k & 1 ) res = res * base % mod;
		base = base * base % mod;
		k >>= 1;
	}
	return res;
}
		
void solve ( int x )
{
	for ( int i = 2 ; i * i <= x ; i ++ )
		if ( x % i == 0 )
		{
			prime[++cnt] = i;
			while ( x % i == 0 )
			{
				c[cnt] ++;
				x /= i;
			}
		}
	if ( x > 1 )
	{
		prime[++cnt] = x;
		c[cnt] ++;
	}
}
		
int inv ( int x ) { return ksm ( x , mod - 2 ); }
		
signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	a = read() , b = read();
	solve ( a );
	for ( int i = 1 ; i <= cnt ; i ++ )
	{
		if ( ( prime[i] - 1 ) % mod == 0 ) { ans = ans * ( b * c[i] + 1 ) % mod; continue; }
		int mu = inv ( prime[i] - 1 );
		int zi = ( ksm ( prime[i] , b * c[i] + 1 ) + mod - 1 ) % mod;
		ans = ans * zi * mu % mod;
	}
	cout << ( ans + mod ) % mod << endl;
	return 0;
}

逆元

ax1(mod b)x的最小整数解 即为amod b 意义下的逆元。

通俗讲,逆元(x1)j即为amod b 下的倒数

求逆元方法:

  1. 根据费马小定理 a×ap21 (mod p)

    所以可以得知ap2即为amod p意义下的逆元

    int ksm ( int x , int k )
    {
    	int base = x , res = 1;
    	while (k) 
    	{
    		if ( k & 1 ) res = res * base % mod;
    		base = base * base % mod;
    		k >>= 1;
    	}
    	return res;
    }
    int inv ( int x ) { return ksm ( x , mod - 2 ); }
    
  2. exgcd求解

    void exgcd ( int aa , int bb , int &x , int &y )
    {
    	if ( !bb ) return x = 1 , y = 0 , void();
    	exgcd ( bb , aa % bb , y , x );
    	y -= aa / bb * x;
    }
    int inv ( int numm , int modd )
    {
    	int x , y;
    	exgcd ( numm , modd , x , y );
    	return ( x % modd + modd ) % modd;
    }
    
  3. 线性方法

    线性求逆元: 以O(n)复杂度求1n的逆元

    设当前数为x, 设模数m=mxx+r 则必有x>r .

    将上式转化为m=mxx+r0(modm)

    两边同乘 x1r1:mxr1+x10(modm)

    移项得x1=mx(r1)modm

    由于x>rr1已知 则x1可求

inv[1] = 1;
for ( int i = 2 ; i <= n ; i ++ ) inv[i] = ( ( m - m / i ) * inv[m%i] + m ) % m;

C. 【例题3】线性求逆元

模板题

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

#define int long long 

const int N = 3e6 + 5;
int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}

int a[N] , n , m , inv[N];

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	n = read() , m = read();
	inv[1] = 1;
	for ( int i = 2 ; i <= n ; i ++ ) inv[i] = ( ( m - m / i ) * inv[m%i] + m ) % m;
	for ( int i = 1 ; i <= n ; i ++ ) cout << inv[i] << endl;
	return 0;
}

中国剩余定理

对于很多组xai (mod mi) 其中mi为两两互质的质数 我们的目标是找出x的最小整数解

我们设Mm1mn的最小公倍数 那么M=i=1nmi

ki=M/mi 并找到ki的逆元bi 那么最小解即为i=1nmikibi (mod M)

证明:(我们要试着构造出这个解)

对于xai (mod mi) 我们设x=ai 显然成立 但是这个解只满足这一个方程 但不一定满足其他的同余方程

所以我两边同乘MmiaiMmiaiMmi(mod mi)(同余的同乘性)

所以当x=aiMmi时 除了第i个方程 所有的1n个方程都满足x0(mod mi) 但是我们为了好算 两面同乘(Mmi)1

所以当x=aiMmi(Mmi)1时 对于第i个方程 xai(mod b) 除了第i个方程的所有方程都满足x0(mod b)

那么我们将所有这样的aiMmi(Mmi)1加起来即可 最终答案就是i=1naiMmi(Mmi)1mod M

根据同余的同加性 一定可以满足所有方程 再mod M得到一个最小解

p.s. mod M的原因:对于每一个方程 你成倍地加上或减去M 对同余性是没有影响的(因为M一定是模数的倍数 所以消掉了)

D. 【例题4】中国剩余定理

模板题 解法见上

观察题解可知这里费马小定理失效(因为模数虽然互质 但是不一定保证是质数) 所以需要用exgcd求解逆元

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long 
const int N = 1e3 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}

int n , a[N] , b[N] , ans = 0 , M = 1 , k[N] , r[N];

//int ksm ( int x , int k , int mod )
//{
//	int ans = 1 , base = x;
//	while (k)
//	{
//		if ( k & 1 ) ans = ans * base % mod;
//		base = base * base % mod;
//		k >>= 1;
//	}
//	return ans;
//}
//
//int inv ( int x , int mm ) { return ksm ( x , mm - 2 , mm ); } 

void exgcd ( int aa , int bb , int &x , int &y )
{
	if ( !bb ) return x = 1 , y = 0 , void();
	exgcd ( bb , aa % bb , y , x );
	y -= aa / bb * x;
}
int inv ( int numm , int modd )
{
	int x , y;
	exgcd ( numm , modd , x , y );
	return ( x % modd + modd ) % modd;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	n = read();
	for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , b[i] = read() , M *= a[i];//模数 余数
	for ( int i = 1 ; i <= n ; i ++ ) k[i] = M / a[i];
	for ( int i = 1 ; i <= n ; i ++ )
		ans = ( ( ans + b[i] * k[i] * inv ( k[i] , a[i] ) ) % M + M ) % M;
	cout << ans % M << endl;
	return 0;
}

posted @   Echo_Long  阅读(176)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示