Junjun algorithm class - Fundamentals of number theory

catalogue

Fundamentals of number theory

to be divisible by

For two integers \ (a \, \ B (a \ NEQ 0) \), if \ (\ exists k\in Z \) makes \ (ak=b \), it is called \ (a \) divisible \ (B \) and recorded as \ (a|b \)

Counting

P1226 [template] fast power | remainder operation

Fast power for fast calculation \ (x^y\ \%\ mod \)

The idea of calculation is: take the decimal \ (y \) as binary, and then count the answers through some operations under binary

The following cases have been defaulted to binary

Process:

For the calculation of \ (x^y \), the \ (Y \) is expressed as binary, such as: \ (105 {(10)} = 1101001 {(2)} \)

So \ (x^y = x^{105} = x^{2^6+2^5+2^3+2^0}=x^{2^6}x^{2^5}x^{2^3}x^{2^0} \)

Use the variable \ (ans \) to count the answers

x ans
\(x\) \(x^{2^0}\)
\(x^2\) \(x^{2^0}\)
\(x^4\) \(x^{2^0}\)
\(x^8\) \(x^{2^3}x^{2^0}\)
\(x^{16}\) \(x^{2^3}x^{2^0}\)
\(x^{32}\) \(x^{2^5}x^{2^3}x^{2^0}\)
\(x^{64}\) \(x^{2^6}x^{2^5}x^{2^3}x^{2^0}\)
int ksm(int x, int y, int mod) {
	int ans = 1;
	for( ; y; y >>= 1, (x *= x) %= mod) if(y & 1) (ans *= x) %= mod;
	return ans;
}

Note: the expression of \ ((a *= b) \%= mod \) is equivalent to \ (a = (a * b) \%mod \)

Time complexity: \ (O(log\ y) \)

gcd

The maximum common divisor of two numbers \ (a \), \ (B \)

Pei Shu theorem

For any \ (x \, \ y \), all \ (\ exists \ a,b \) satisfy \ (ax+by=gcd(x,y) \)

application

Used to do questions

Can be used to prove strange things and push formulas

In information, the common routine for this thing is enumeration \ (gcd \)

For example, give you T groups of data and find \ (\ sum {I = 1} ^ n \ sum {J = 1} ^ m GCD (I, J) \)

One step is the standard enumeration \ (gcd \)

\(\displaystyle \ \sum_{i=1}^n \sum_{j=1}^m gcd(i,j)\)

\(=\displaystyle \sum_{i=1}^n \sum_{j=1}^m \sum_{d|i,j}d[gcd(\frac id,\frac jd)==1]\)

\(\mathcal{Code}:\)

int Gcd(int x, int y) { return y ? Gcd(y, x % y) : x; }

extended euclidean algorithm

P1082 [NOIP2012 improvement group] congruence equation

Algorithm description

Integer solution for solving the equation \ (ax+by = gcd(a, b) \) about \ (x,y \)

The necessary condition for the solution of equation \ (ax + by = m \) is \ (m\ mod\ gcd(a, b) = 0 \)

prove:

Easily obtained from known conditions: \ (a\ mod\ gcd(a, b) = 0,b\ mod\ gcd(a, b) = 0 \)

Then \ ((ax + by)\ mod\ gcd(a, b) = 0 \)

That is \ (m\ mod\ gcd(a, b) = 0 \)

Pre knowledge: Euclidean algorithm (rolling Division)

Euclidean algorithm is used to solve the greatest common factor of two numbers

int Gcd(int x, int y) { return y ? Gcd(y, x % y) : x; }

\[ax_1 + by_1 = gcd(a, b) \]

If we already know the following formula

\[bx_2 + (a\%b)y_2 = gcd(b, a \% b) \]

It can be concluded that

\[ax_1 + by_1 = bx_2 + (a\%b)y_2 \]

\[ax_1 + by_1 = bx_2 + (a - a / b * b)y_2 \]

\[ax_1 + by_1 = ay_2 + b(x_2 - a/b*y_2) \]

Then there

\[x_1 = y_2,\ y_1 = x_2 - a / b * y_2 \]

When \ (b = 0 \) \ (ax = a \)

At this time \ (y \) is better to take \ (0 \), because during backtracking, \ (y \) increases rapidly and the value is easy to cross the boundary

int Ex_gcd(int a, int b, int &x, int &y) {
	if(b == 0) return x = 1, y = 0, a;
	int ans = Ex_gcd(b, a % b, x, y);
	int tmp = x;
	x = y; y = tmp - a / b * y;
	return ans;
}

In this way, a set of solutions of equation \ (ax+by=gcd(a, b) \) can be found

To solve a set of solutions in which \ (x \) is the smallest positive integer, it can be derived from the following formula

\[ax + by = 1 \]

\[ax + by + k * ba - k * ba = 1 \]

\[a(x + k*b) + b(y - k * a) = 1 \]

Then \ (x = (x \% b + b) \% b \)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int read() {
	int x = 0, f = 1; char ch;
	while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 3) + (x << 1) + (ch ^ 48));
	return x * f;
}
template <class T> T Max(T a, T b) { return a > b ? a : b; }
template <class T> T Min(T a, T b) { return a < b ? a : b; }
int Ex_gcd(int a, int b, int &x, int &y) {
	if(b == 0) return x = 1, y = 0, a;
	int ans = Ex_gcd(b, a % b, x, y);
	int tmp = x;
	x = y; y = tmp - a / b * y;
	return ans;
}
int main() {
	int a = read(), b = read(), x, y;
	Ex_gcd(a, b, x, y);
	x = (x % b + b) % b;
	printf("%d\n", x);
	return 0;
}

Example: P1516 frog date

lcm

There's really nothing to say about this

\(lcm \) this thing is rejected because it has no nature in number theory

Usually convert \ (lcm \) to \ (gcd \): \ (lcm(i,j)=\frac {i*j}{gcd(i,j)} \)

Note that this property is valid only when there are two numbers, but not necessarily in other cases, such as

\(\frac {1*2*3*4*5}{gcd(1,2,3,4,5)} = 1*2*3*4*5 \neq lcm(1,2,3,4,5)\)

Example: P1891 crazy LCM

congruence

For two integers \ (a \, \ b \), if \ (\ exists \ p \in prime \) makes \ (a\%p == b \% p \), it is said that \ (a \) and \ (b \) are congruent in the sense of module \ (p \)

If represented by a symbol, it is \ (a \equiv b \ (mod \ p) \)

nature

Symmetry: $a \equiv b \ (mod \ p) \ \Rightarrow \ b \equiv a \ (mod \ p)$

Multiplicity: if \ (a \ equiv B \ (MOD \ P) \, \ C \ equiv D \ (MOD \ P) \), then \ (ac \equiv bd \ (mod \ p) \)

application

The information is basic and has no application. It is mainly used in the proof and expression of theorems

For the congruence \ (a \equiv b \ (mod \ p) \), it can be converted to \ (a x+km=b \) and exgcd can be applied

In particular, a solution to the congruence \ (a \equiv 1 \ (mod \ p) \) is the inverse of \ (a \) in the sense of module \ (p \)

Inverse element

For integers \ (a, p \), if \ (\ exists \ a^{-1} \) satisfies \ (a*a^{-1} \ \equiv \ 1(mod \ p) \), it is said that \ (a^{-1} \) is the inverse of \ (a \) in the sense of module \ (p \)

It is mainly used for division module problem

Because division is not closed to modular operation, inverse element arises at the historic moment

There are mainly two methods to find the inverse element, one is Fermat's small theorem, the other is \ (EX gcd \), and the third is linear

Only linear codes are listed

\(\mathcal{Code}:\)

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

Example: P3811 multiplicative inverseP5431 multiplicative inverse 2

Eratoseni sieve method

Complexity $\ theta (n logn)$

Therefore, it is recommended to use Euler sieve \ (\ Theta(n) \)

Let's talk about the principle here

For a number \ (a \), then \ (k*a \ (k \in N ^ *) \) will not enter the prime table in the subsequent cycle, so mark them

The complexity is not as good as that of Euler sieve because the Ehrlich sieve will repeat the sieve for some numbers

\(\mathcal{Code}:\)

void calc(){
    for(int i = 2; i <= n; ++ i) {
        if(! vis[i]) prime[++ cnt] = i;
        for(int j = 1; j <= cnt; ++ j) {
            if(i * prime[j] <= n) vis[i * prime[j]] = 1;
        }
    } 
}

Example: P3383 linear sieve prime

Du Jiao sieve

For a product function \ (f \), we require \ (\ displaystyle \ sum {I = 1} ^ NF (I) \)

\(\mathcal{Ans}\):

Let \ (S(n)=\displaystyle\sum_{i=1}^n f(i) \), \ (h=g*f\) (h, G are any integral function)

Then \ (\ displaystyle \ sum \ limits {I = 1} ^ {n} (f * g) (I) \)
\(\begin{aligned} &= \sum\limits_{i=1}^{n} \sum \limits _{d|i} g(d)f(\frac{i}{d}) \\ &= \sum \limits _{d=1}^{n} g(d)\sum\limits _{i=1}^{\lfloor \frac{n}{d}\rfloor } f(i) \\ &= \sum \limits _{d=1}^{n} g(d) S(\lfloor \frac{n}{d} \rfloor) \end{aligned}\)

Also \ (\ displaystyle g (1) s (n) = \ sum {d = 1} ^ ng (d) s (\ lfloor \ frac nd \ rfloor) - \ sum {d = 2} ^ ng (d) s (\ lfloor \ frac nd \ rfloor) \)

Then \ (\ displaystyle g (1) s (n) = \ sum \ limits {I = 1} ^ {n} (f * g) (I) - \ sum {d = 2} ^ ng (d) s (\ lfloor \ frac nd \ rfloor) \)

Preprocess \ (\ & \) number theory blocks

Example: P4213 Du Jiao sieve

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
const int N = 6e6 + 5;
typedef long long LL;
bool vis[N];
int t, cnt, mu[N], phi[N], prime[N], sum1[N];
LL n, sum2[N];
map<int, int> m1;
map<LL, LL> m2;
inline void prim(int x) {
	mu[1] = phi[1] = 1;
	for(int i = 2; i <= x; i ++) {
		if(vis[i] == 0) {
			prime[++ cnt] = i;
			mu[i] = -1, phi[i] = i - 1;
		}
		for(int j = 1; j <= cnt && i * prime[j] <= x; j ++) {
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			else mu[i * prime[j]] = - mu[i], phi[i * prime[j]] = phi[i] * (prime[j] - 1);
		}
	}
	for(int i = 1; i <= x; i ++) sum1[i] = sum1[i-1] + mu[i], sum2[i] = sum2[i-1] + phi[i];
}
int djsmu(int x) {
	if(x <= 6e6) return sum1[x];
	if(m1[x]) return m1[x];
	int ans = 1;
	for(int l = 2, r; l <= x; l = r + 1) {
		r = x/(x/l);
		ans -= (r - l + 1) * djsmu(x/l);
	}
	return m1[x] = ans;
}
LL djsphi(LL x) {
	if(x <= 6e6) return sum2[x];
	if(m2[x]) return m2[x];
	LL ans = x * (x + 1) / 2;
	for(int l = 2, r; l <= x; l = r + 1) {
		r = x/(x/l);
		ans -= (r - l + 1) * djsphi(x/l);
	}
	return m2[x] = ans;
}
int main() {
	scanf("%d", &t);
	prim(6000000);
	while(t --> 0) {
		scanf("%lld", &n);
		printf("%lld %d\n", djsphi(n), djsmu(n));
	}
	return 0;
}

Lagrange interpolation

Sun Tzu theorem

If \ (m_1,m_2,\cdots,m_n \) is a positive integer with two coprime, \ (M=\prod_{i=1}^n{m_i} \), \ (m_i = m / m_i \), \ (t_i \) is a solution of the linear congruence equation \ (M_it_i\equiv 1 \ (mod \ m_i) \)

For any n integers \ (a_1,a_2,\cdots,a_n \), the Congruence Equations: \ (\ begin{cases}x ≡ a_1(mod\ m_1)\x ≡ a_2(mod\ m_2)\ \cdots \cdots\x ≡ a_n(mod\ m_n)\end{cases} \) have integer solutions

The solution of the system of equations is \ (x = \ sum {I = 1} ^ n M_it_i a_i \), and has a unique solution in the sense of \ (\% \ M \).

prove

Because \ (M_i=M/m_i \) is a multiple of all modules except \ (m_i \), so \ (\ forall \ K \ not = I \, \ m_it_ia_i \ equiv 0 \ (MOD \ m_k) \)

Because \ (M_it_ia_i\equiv a_i\ (mod \ m_i) \)
So \ (x=\sum_{i=1}^n M_it_i a_i \)

conclusion

\(CRT \) gives a special solution of a system of Linear Congruence Equations with two coprime modules. The general solution of the equations can be expressed as \ (x+kM\ (k\in Z) \). Some problems require us to find the minimum nonnegative integer solution. We only need to modulo \ (x \) to \ (M \) and let x fall within \ ([1,M) \).

text

For a polynomial \ (f(x) \), its image passes through \ (n \) points \ ((x_i,y_i) \) in the coordinate system

We consider the "Sun Tzu theorem" for this polynomial:

Construct \ (n \) polynomials \ (g_i(n) \). For the \ (I \) th polynomial, for \ (\ forall k\not= i, g_i(x_k)=0 \), and \ (g_i(x_i)=1 \), that is \ (g_i(x_i)*y_i=y_i \)

Then \ (g_i(x)=\frac{(x-x_1)(x-x_2)\cdots(x-x_{i-1})(x-x_{i+1})\cdots(x-x_n)}{(x_i-x_1)(x_i-x_2)\cdots(x_i-x_{i-1})(x_i-x_{i+1})\cdots(x_i-x_n)} \)

So \ (\ displaystyle f(x)=\sum_{i=1}^n g_i(x)*y_i \)

\(\mathcal{Code}\):

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const LL N = 2e3 + 5, mod = 998244353;
LL n, k, ans, x[N], y[N];
LL ksm(LL a, LL b) {
	int res = 1;
	for( ; b ;a = a * a % mod, b >>= 1) {
		if(b & 1) res = res * a % mod;
	}
	return res;
}
LL Lagrange(LL k) {
	LL ans = 0;
	for(int i = 1;i <= n;i ++) {
		LL res = 1;
		for(int j = 1;j <= n;j ++) {
			if(i == j) continue;
			res = (res * ((x[i] + mod - x[j])%mod)) % mod;
		}
		res = ksm(res, mod - 2);
		for(int j = 1;j <= n;j ++) {
			if(i == j) continue;
			res = (res * ((k + mod - x[j])%mod)) % mod;
		}
		res = res * y[i] % mod;
		ans = (ans + res) % mod;
	}
	return ans;
}
int main() {
	cin >> n >> k;
	for(int i = 1;i <= n;i ++) cin >> x[i] >> y[i];
	cout << Lagrange(k) << endl;
	return 0;
}

Example: P4781 Lagrange interpolation

Tags: Math

Posted on Sat, 06 Nov 2021 15:05:02 -0400 by bschwarz