返回顶部

数论专题

持续更新

A - 乘法逆元

\(1∼n\) 中的所有数在模 \(p\) 意义下的乘法逆元

1.快速幂

根据欧拉定理,若\(a\)\(p\)互质,则\(a^{\varphi(p)}\equiv1\;(mod\;p)\),当\(p\)是质数,则满足:
\(p\) 为质数, \(a\) 为正整数, \(a\)\(p\) 互质, 则\(a^{p-1} \equiv 1\;(mod\;p)\).
根据费马小定理: \(a \times a^{p-2} \equiv 1\;(mod \; p)\), \(a^{p-2}\;(mod\;p)\)即为\(a\)的逆元, 利用快速幂求解即可.


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
int n, p;

int pow_mod(int a, int b, int p)
{
	int res = 1;
	while(b)
	{
		if(b & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		b >>= 1;
	}
	return res;
}

int main()
{
	scanf("%d%d", &n, &p);
	for(int i = 1; i <= n; ++ i)
		printf("%d\n", pow_mod(i, p - 2, p));
	return 0;	
} 

2.扩展欧几里得

\(a\)\(p\)互质,但\(p\)不是质数时,解线性同余方程\(a*x\equiv1\;(mod\;p)\):
转化为:\(a*x+p*y\equiv1\),因为\(a\)\(p\)互质,所以一定有解,用exgcd求解即可
exgcd解出的逆元有可能是负数,转化成\(mod\;p\)意义下的正数即可


#include <bits/stdc++.h>
using namespace std;

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

int main()
{
	int n, p;
	scanf("%d%d", &n, &p);
	for(int i = 1; i <= n; ++ i)
	{
		int x, y;
		exgcd(i, p, x, y);
		x = (x % p + p) % p;
		printf("%d\n", x);
	}
	return 0;
} 

3.线性递推

\(p = k * i + r\), \(k\)\(\dfrac{p}{i}\)的商,\(r\)是余数
\(k*i+r\equiv0\;(mod\;p)\), 两边同时乘上\(i^{-1}\)\(r^{-1}\)
\(k * r^{-1} + i^{-1} \equiv 0\;(mod\;p)\)
\(i^{-1} \equiv -k * r^{-1}\;(mod\;p)\)
\(i^{-1} \equiv -\left\lfloor\dfrac{p}{i}\right\rfloor * (p\;mod\;i)^{-1}\;(mod\;p)\)
且已知\(1^{-1}\equiv1\;(mod\;p)\),则可以线性递推


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 3e6 + 20; 
int inv[N];

int main()
{
	int n, p;
	scanf("%d%d", &n, &p);
	inv[1] = 1; puts("1");
	for(int i = 2; i <= n; ++ i)
	{
		inv[i] = (LL)(p - p / i) * inv[p % i] % p;
		printf("%d\n", inv[i]);
	}
	return 0;
}

B - 除数函数求和 1

\(\sigma_k(n) = \sum_{d|n}d^k\), 求\(\sum_{i=1}^n\sigma_k(i)\)的值对\(10^9 + 7\)取模的结果.

考虑每个因子\(d\)对答案的贡献,即\(\sum\limits_{i = 1}^n i^k * \left\lfloor\dfrac{n}{i}\right\rfloor\)
然后暴力处理\(i^k\),复杂度\(O(nlogk)\)


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int P = 1e9 + 7;

int pow_mod(int a, int b, int p)
{
	int res = 1;
	while(b) 
	{
		if(b & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		b >>= 1;
	}
	return res;
}

int main()
{
	int n, k;
	scanf("%d%d", &n, &k);
	int res = 0;
	for(int i = 1; i <= n; ++ i)
		res = (res + (LL)n / i * pow_mod(i, k, P) % P) % P;
	printf("%d", res);
	return 0;
}

考虑继续优化:在求幂时有重复计算,因为每个数都可以唯一分解,所以只需要计算质因子的幂即可
考虑线性筛,用每个数的质因子的幂去计算它的幂.


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int P = 1e9 + 7;
const int N = 1e7 + 10;

bool st[N];
int primes[N], cnt;
int mi[N];

int pow_mod(int a, int b, int p)
{
	int res = 1;
	while(b) 
	{
		if(b & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		b >>= 1;
	}
	return res;
}

void init(int n, int k)
{
	mi[1] = 1;
	for(int i = 2; i <= n; ++ i)
	{
		if(!st[i]) 
		{
			primes[cnt ++ ] = i;
			mi[i] = pow_mod(i, k, P); 
		}
		for(int j = 0; primes[j] * i <= n; ++ j)
		{
			st[primes[j] * i] = 1;
			mi[primes[j] * i] = (LL)mi[i] * mi[primes[j]] % P;
			if(i % primes[j] == 0) break;
		}
	}
}

int main()
{
	int n, k;
	scanf("%d%d", &n, &k);
	init(n, k);
	int res = 0;
	for(int i = 1; i <= n; ++ i)
		res = (res + (LL)n / i * mi[i] % P) % P;
	printf("%d\n", res);
	return 0;
}

C - 除数函数求和 2

\(\sigma_k(i) = \sum_{d|i}d^k\)
\(\sum_{i=1}^n2\sigma_2(i)+3\sigma_1(i)+5\sigma_0(i)\)\(998244353\)取模.

和上题一样考虑每个因子的贡献,转化为求\(\sum\limits_{i=1}^n(2i^2+3i+5) * \left\lfloor\dfrac{n}{i}\right\rfloor\)
\(n\)的范围在\(10^9\)内,考虑整除分块
转化为\(2\sum\limits_{i=1}^ni^2\left\lfloor\dfrac{n}{i}\right\rfloor + 3\sum\limits_{i=1}^ni\left\lfloor\dfrac{n}{i}\right\rfloor + 5\sum\limits_{i=1}^n\left\lfloor\dfrac{n}{i}\right\rfloor\)
且已知:
\(\sum\limits_{i=1}^n1=n\)
\(\sum\limits_{i=1}^ni=\dfrac{(1+n)*n}{2}\)
\(\sum\limits_{i=1}^ni^2=\dfrac{n*(n+1)*(2n+1)}{6}\)
注:运算都是在\(mod\;p\)意义下的,故除法要乘逆元;且做减法后可能会出现负数,转化为\(mod\;p\)意义下的正数


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int P = 998244353;
const int inv3 = 332748118;
const int inv2 = 499122177;
 
int g(int k, int x)
{
	return k / (k / x);	
}

int f2(int l, int r)
{
	int res1 = 1, res2 = 1;
	l --;
	res1 = (LL)res1 * l % P;
	res1 = (LL)res1 * (l + 1) % P;
	res1 = (LL)res1 * (2 * l + 1) % P;
	res2 = (LL)res2 * r % P;
	res2 = (LL)res2 * (r + 1) % P;
	res2 = (LL)res2 * (2 * r + 1) % P;
	int res = res2 - res1;
	res = (res % P + P) % P;
	res = (LL)res * inv3 % P;
	return res; 
} 

int f1(int l, int r)
{
	int res = 1;
	res = (LL)res * (l + r) % P;
	res = (LL)res * (r - l + 1) % P;
	res = (LL)res * 3 % P;
	res = (LL)res * inv2 % P;
	return res; 
}

int f0(int l, int r)
{
	int res = 1;
	res = (LL)res * (r - l + 1) % P;
	res = (LL)res * 5 % P;
	return res; 
} 

int main()
{
	int n;
	scanf("%d", &n);
	int res = 0;
	for(int l = 1, r; l <= n; l = r + 1)
	{
		r = min(n, g(n, l));
		res = (res + (LL)f0(l, r) * (n / l) % P) % P;
		res = (res + (LL)f1(l, r) * (n / l) % P) % P;
		res = (res + (LL)f2(l, r) * (n / l) % P) % P;
	}
	printf("%d\n", res);
	return 0;
} 

D - 质数判定

判定输入的数是不是质数。

Miller_Rabin判质数,要用__int128或者快速乘


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;

/*
LL mul(LL a, LL b, LL p)
{
    __int128 x = a, y = b, m = p;
    return (LL)(x * y % m);
}
*/

LL mul(ULL a, ULL b, LL p) 
{
    return (a * b - (ULL)((LD)a / p * b) * p + p) % p;
}

/*
LL mul(LL a, LL b, LL p)
{
	LL res = 0;
	while(b)
	{
		if(b & 1) res = (res + a) % p;
		a = a * 2 % p;
		b >>= 1;
	}
	return res;
}
*/

LL power(LL a, LL b, LL p)
{
	LL res = 1;
	while(b)
	{
		if(b & 1) res = mul(res, a, p);
		a = mul(a, a, p);
		b >>= 1;
	}
	return res;
}

LL p[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};

bool Miller_Rabin(LL n)
{
	if(n == 1) return 0;
	for(int i = 1; i <= 9; ++ i)
	{
		if(p[i] == n) return 1;
		else if(p[i] > n) return 0;
		LL sum = power(p[i], n - 1, n), x = n - 1;
		if(sum != 1) return 0;
		while(sum == 1 && !(x % 2))
		{
			x >>= 1; 
			sum = power(p[i], x, n);
			if(sum != 1 && sum != n - 1) return 0;
		}
	}
	return 1;
}

int main()
{
	LL n; 
	while(scanf("%lld", &n) == 1)
	{	
		puts(Miller_Rabin(n) ? "Y" : "N");
	}
	return 0;
}

E - 乘法逆元 2

\(\sum_{i=1}^na_i^{-1}\times998244353^{n-i}\;(mod\;p)\)
\(1 \le n \le 5000000,\;1\le a_i < p,\; p=10^9 + 7\)

解决此题之前先考虑如何\(O(n)\)求阶乘的逆元
考虑如下递推式:
\(infact[n]\)\(n!\)的逆元
\(infact[i + 1] = \dfrac{1}{(i + 1)!}\)
\(infact[i + 1] * (i + 1) = \dfrac{1}{i!} = infact[i]\)
故我们可以求出\(n!\)的逆元,然后逆推,得到\(1...n!\)所有的逆元
同理,还可以用\(infact[i] * (i - 1)! = i^{-1}\)\(O(n)\)得到所有\(i\)的逆元


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 3e6 + 20;

int fact[N], infact[N];

int pow_mod(int a, int b, int p)
{
	int res = 1;
	while(b)
	{
		if(b & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		b >>= 1;
	}
	return res;
}

int main()
{
	int n, p;
	scanf("%d%d", &n, &p);
	fact[0] = 1;
	for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * i % p;
	
	infact[n] = pow_mod(fact[n], p - 2, p);
	
	for(int i = n - 1; i >= 1; -- i)
		infact[i] = (LL)infact[i + 1] * (i + 1) % p;
	
	for(int i = 1; i <= n; ++ i)
	{
		int res = (LL)infact[i] * fact[i - 1] % p;
		printf("%d\n", res);
	}
	return 0;
} 

本题可以考虑相同的思路
做前缀积 \(fact[n] = \prod\limits_{i=1}^na_i\)
求出\(infact[n]\),用\(infact[i + 1] * a_{i + 1} = infact[i]\)递推所有前缀积的逆元
然后用\(infact[i] * fact[i - 1] = a_i^{-1}\)\(O(n)\)得到所有\(a_i\)的逆元


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int P = 1e9 + 7;
const int M = 998244353;
const int N = 5e6 + 20;

int a[N];
int fact[N], infact[N];

int pow_mod(int a, int b, int p)
{
	int res = 1;
	while(b)
	{
		if(b & 1) res = (LL)res * a % p;
		a = (LL)a * a % p;
		b >>= 1;
	}
	return res;
}

int main()
{
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);

	fact[0] = 1;
	for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * a[i] % P;
	
	infact[n] = pow_mod(fact[n], P - 2, P);
	
	for(int i = n - 1; i >= 1; -- i)
		infact[i] = (LL)infact[i + 1] * a[i + 1] % P;
	
	int ans = 0;
	for(int i = 1; i <= n; ++ i)
	{
		int res = (LL)infact[i] * fact[i - 1] % P;
		ans = (LL)ans * M % P;
		ans = ((LL)ans + res) % P;
	}
	printf("%d\n", ans);
	return 0;
} 

F - 快速幂 2

\(x^{a_i}\;(mod\;p)\)
\(1 \le n \le 5 \times 10^6,\;1\le x,a_i < p,\; p = 998244352\)

直接暴力快速幂的复杂度\(O(nlogp)\)
考虑分块预处理
\(y = \left\lfloor\dfrac{y}{k}\right\rfloor \cdot k + y \;mod\; k\)
\(x^y = x^{y\;mod\;k} \cdot x^{\left\lfloor\dfrac{y}{k}\right\rfloor \cdot k}\)
预处理复杂度\(O(k + \dfrac{p}{k})\), 当\(k\)\(\sqrt p + 1\)时最优
预处理后即可\(O(1)\)回答每个询问


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 5e6 + 20;
const int P = 998244352;

int a[N], x_i[N], x_ki[N];
int x, n;

int main()
{
	scanf("%d%d", &x, &n);
	int k = sqrt(P) + 1;
	x_i[0] = 1;
	for(int i = 1; i <= k; ++ i) x_i[i] = (LL)x_i[i - 1] * x % P;
	x_ki[0] = 1;
	for(int i = 1; i <= P / k; ++ i) x_ki[i] = (LL)x_ki[i - 1] * x_i[k] % P;
	for(int i = 1; i <= n; ++ i)
	{
		int y;
		scanf("%d", &y);
		int res = (LL)x_i[y % k] * x_ki[y / k] % P; 	
		printf("%d ", res);
	}
	puts("");
	return 0;
} 

G - 二项卷积

H - 模立方根

I - ZQC 的作业

J - Humble Numbers

求第\(n\)个质因子只有\(2,3,5,7\)的数


#include <bits/stdc++.h>
using namespace std;

const int N = 6000;

int f[N];

void init()
{
	f[1] = 1;
	int a = 1, b = 1, c = 1, d = 1;
	for(int i = 2; i <= 5842; ++ i)
	{
		f[i] = min(min(f[a] * 2, f[b] * 3), min(f[c] * 5, f[d] * 7));
		if(f[i] == f[a] * 2) a ++;
		if(f[i] == f[b] * 3) b ++;
		if(f[i] == f[c] * 5) c ++;
		if(f[i] == f[d] * 7) d ++;
	}	
}

int main()
{
	init();
	int n;
	while(scanf("%d", &n) == 1 && n)
	{
		if(n % 10 == 1 && n % 100 != 11) printf("The %dst humble number is %d.\n", n, f[n]);
		else if(n % 10 == 2 && n % 100 != 12) printf("The %dnd humble number is %d.\n", n, f[n]);
		else if(n % 10 == 3 && n % 100 != 13) printf("The %drd humble number is %d.\n", n, f[n]);
		else printf("The %dth humble number is %d.\n", n, f[n]);
	} 
	return 0;
} 

K - X问题

求在小于等于\(N\)的正整数中有多少个\(X\)满足:
\(X\;mod\;a_0=b_0,\;X\;mod\;a_1=b_1,\;X\;mod\;a_2=b_2,\;…,\;X\;mod\;a_i=b_i,\;…\;(0 < a_i \le 10)\)

扩展中国剩余定理, 去掉了模数两两互质的条件
先从两个方程入手
\(\begin{cases}x = k_1a_1 + m_1\\x = k_2a_2 + m_2\end{cases}\)
\(k_1a_1 + m_1 = k_2a_2 + m_2\)
\(k_1a_1 - k_2a_2 = m_2 - m_1\)
\((a_1,a_2)\;|\;(m_2 - m_1)\),则有解
通解\(\begin{cases}k_1 + k\dfrac{a_2}{d}\\k_2 + k\dfrac{a_1}{d}\end{cases}\)
\(x = k_1a_1 + m_1 = (k_1 + k\dfrac{a_2}{d})a_1 + m_1\)
\(x = a_1k_1 + m_1 + k[a_1, a_2]\)
\(a_1k_1 + m_1 = m\), \([a_1, a_2] = a\)
\(x = m + ka\)
则将两个不定方程合并成了一个,合并\(n - 1\)次后只剩一个方程
即为 \(x \equiv m\;(mod\;a)\)
最小正整数解即为\(m\;mod\;a\)的正余数,然后即可求出小于等于\(N\)的正整数中\(x\)的个数.


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 10 + 2;

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

LL a[N], b[N];

int main()
{
	int __;
	scanf("%d", &__);
	while(__ -- )
	{
		LL n, m;
		scanf("%lld%lld", &m, &n);
		for(int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
		for(int i = 1; i <= n; ++ i) scanf("%lld", &b[i]);
		
		LL a1 = a[1], m1 = b[1];
	
		bool flag = 0;
		for(int i = 2; i <= n; ++ i)
		{
			LL a2 = a[i], m2 = b[i];
			LL k1, k2;
			LL d = exgcd(a1, a2, k1, k2);
			if((m2 - m1) % d) { flag = 1; break; }
			k1 *= (m2 - m1) / d;
			LL t = a2 / d;
			k1 = (k1 % t + t) % t;
			m1 = a1 * k1 + m1;
			a1 = abs(a1 / d * a2); 
		}
		if(flag) puts("0");
		else 
		{
			LL res = (m1 % a1 + a1) % a1;
			if(res > m) puts("0");
			else if(res == 0) printf("%lld\n", (m - res) / a1);
			else printf("%lld\n", (m - res) / a1 + 1);
		}
	}
	return 0;
}

L - GCD

求满足\(a \le x \le b,\;c \le y \le d,\;gcd(x, y) = k\)\((x,y)\)数量.
且(5,7)和(7,5)被认为是相同的.


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e5 + 20;

int primes[N], cnt, mu[N], sum[N];
bool st[N]; 

void init()
{
	mu[1] = 1;
	for(int i = 2; i < N; ++ i)
	{
		if(!st[i]) 
		{
			primes[cnt ++ ] = i;
			mu[i] = -1;
		}
		for(int j = 0; primes[j] * i < N; ++ j)
		{
			st[primes[j] * i] = 1;
			if(i % primes[j] == 0) break;
			mu[primes[j] * i] = -mu[i];
		}
	}
	for(int i = 1; i < N; ++ i) sum[i] = sum[i - 1] + mu[i]; 
}

int g(int k, int x)
{
	return k / (k / x);	
}

LL f(int a, int b, int k)
{
	LL res1 = 0, res2 = 0;
	a = a / k, b = b / k;
	int n = min(a, b);
	for(int l = 1, r; l <= n; l = r + 1)
	{
		r = min(n, min(g(a, l), g(b, l)));
		res1 += (LL)(sum[r] - sum[l - 1]) * (a / l) * (b / l);
	}	
	for(int l = 1, r; l <= n; l = r + 1)
	{
		r = min(n, g(n, l));
		res2 += (LL)(sum[r] - sum[l - 1]) * (n / l) * (n / l);
	}
	return res1 - res2 / 2;	
}

int main()
{
	init();
	int __, cnt = 0;
	scanf("%d", &__);
	while(__ -- )
	{
		int a, b, c, d, k;
		scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
		if(k == 0) { printf("Case %d: 0\n", ++ cnt); continue; }
		LL res = f(b, d, k) - f(a - 1, d, k) - f(b, c - 1, k) + f(a - 1, c - 1, k);
		printf("Case %d: %lld\n", ++ cnt,res);
	}
	return 0;
}

M - GCD Again


#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n;
	while(scanf("%d", &n) == 1 && n)
	{
		int res = n, m = n;
		for(int i = 2; i <= n / i; ++ i)
		{
			if(n % i == 0)
			{
				while(n % i == 0) n /= i;
				res = res / i * (i - 1);
			}
		}
		if(n > 1) res = res / n * (n - 1);
		printf("%d\n",m - res - 1);
	}
	return 0; 
} 

N - The Euler function

\(\sum\limits_{i=a}^bφ(i)\)

欧拉函数是积性函数,用线性筛预处理即可


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 3e6 + 20;

int primes[N], cnt;
int phi[N];
bool st[N];

void get_euler(int n)
{
	phi[1] = 1;
	for(int i = 2; i <= n; ++ i)
	{
		if(!st[i]) 
		{
			phi[i] = i - 1;
			primes[cnt ++] = i;
		}
		for(int j = 0; primes[j] <= n / i; ++ j)
		{
			st[primes[j] * i] = 1;
			if(i % primes[j] == 0)
			{
				phi[i * primes[j]] = phi[i] * primes[j];
				break;
			}
			phi[primes[j] * i] = phi[i] * (primes[j] - 1);
		}
	}
}

int main()
{
	get_euler(N - 1);
	int a, b;
	while(scanf("%d%d", &a, &b) == 2)
	{
		LL res = 0;
		for(int i = a; i <= b; ++ i)
			res += phi[i];
		printf("%lld\n", res);
	}
	return 0;
}

O - Fansblog

P - Discrete Logging


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> 
using namespace std;

const int N = 2e5 + 3;
const int null = 0x3f3f3f3f; 
typedef long long LL; 

int Hash[N], h[N];

int find(int x)
{
	int k = (x % N + N) % N;
	
	while(Hash[k] != null && Hash[k] != x)
	{
		k ++;
		if(k == N) k = 0;
	}
	
	return k;
} 

bool count(int x)
{
	int k = (x % N + N) % N;
	while(1)
	{
		if(Hash[k] == null) return 0;
		if(Hash[k] == x) return 1;
		k ++;
		if(k == N) k = 0;
	}
	return 0;
}

int bsgs(int a, int b, int p)
{
	memset(Hash, 0x3f, sizeof Hash);
	if(1 % p == b % p) return 0;
	int k = sqrt(p) + 1;
	for(int i = 0, j = b % p; i < k; ++ i) 
	{
		int k = find(j);
		Hash[k] = j;
		h[k] = i;
		j = (LL)j * a % p;
	}
	int ak = 1;
	for(int i = 0; i < k; ++ i) ak = (LL)ak * a % p;
	for(int i = 1, j = ak % p; i <= k; ++ i)
	{
		if(count(j)) return (LL)i * k - h[find(j)];
		j = (LL)j * ak % p;
	}
	return -1;
}

int main()
{
	int a, p, b;
	while(scanf("%d%d%d", &p, &a, &b) == 3)
	{
		if(a == 0 && p == 0 && b == 0) break;
		int res = bsgs(a, b, p);
		if(res == -1) puts("no solution");
		else printf("%d\n", res);
	}
	return 0;
}

Q - The Embarrassed Cryptographer

R - Minimum Sum LCM

S - GCD - Extreme (I)

T - Colossal Fibonacci Numbers!

U - One Friend at a Time

V - X^A Mod P

W - 乘法逆元

\(M\)\(N\)互质,求满足K * M % N = 1的最小正整数K.

同A题,扩展欧几里得求逆元


#include <bits/stdc++.h>
using namespace std;

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

int main()
{
	int n, m;
	scanf("%d%d", &m, &n);
	int x, y;
	int d = exgcd(m, n, x, y);
	printf("%d\n", (x % n + n) % n);
	return 0;
}

X - 中国剩余定理

一个正整数\(K\),给出\(K\;Mod\;\)一些质数的结果,求符合条件的最小的\(K\)

中国剩余定理
\(\begin{cases}x \equiv a_1\;(mod\;m_1)\\x \equiv a_2\;(mod\;m_2)\\...\\x \equiv a_k\;(mod\;m_k)\end{cases}\)
\(M = m_1m_2...m_k\)
\(M_i = \dfrac{M}{m_i}\)
\(M_i^{-1}\)表示\(M_i\)\(mod\;m_i\)条件下的逆元
\(x = a_1M_1M_1^{-1} + a_2M_2M_2^{-1} + ... + a_kM_kM_k^{-1}\)


#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 10 + 2;
int n;
int A[N], B[N];

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

int main()
{
	scanf("%d", &n);
	LL M = 1;
	for(int i = 0; i < n; ++ i)
	{
		scanf("%d%d", &A[i], &B[i]);
		M *= A[i];
	}
	
	LL res = 0;
	for(int i = 0; i < n; ++ i)
	{
		LL Mi = M / A[i];
		LL ti, y;
		exgcd(Mi, A[i], ti, y);
		res += B[i] * Mi * ti;
	}
	printf("%lld\n", (res % M + M) % M);
	return 0;
} 
posted @ 2021-01-22 11:54  __October  阅读(118)  评论(0编辑  收藏  举报