Number theory template and reasoning process

Posted by trilbyfish on Sun, 06 Feb 2022 22:33:04 +0100

I Prime number

1. Determine prime number by trial division

The factors of a number appear in pairs. We can judge the smaller one
It should be noted that I < = sqrt (x) or I * I < = x should not be used as far as possible. First, it is to reduce the operation and second, it is to prevent exceeding the int range

bool is_prime(int x)
{
	if (x < 2)return false;
	for (int i = 2; i <= n / i; i++)
		if (n % i == 0)return false;
	return true;
}

2. Decomposition quality factor

According to the basic theorem of arithmetic: each positive integer can be expressed in a unique way by the product of its prime factor
n=p1^a1 * p2^a2 * p3^a3...
If there is a factor greater than Sqn in the multiplication method, it must be proved that there is at most one factor greater than sqrt
For example, if n=16, 16/2 still has a multiple of 2, so it is dried in a circular way. Finally, if n > 1, it means that this is the only prime factor greater than sqrt(n).

void divide(int n)
{
	for (int i = 2; i <= n / i; i++)
	{
		if (n % i == 0)
		{
			int s = 0;//s is the number of times
			while (n % i == 0)
			{
				n /= i;
				s++;
			}
			cout << i << ' ' << s << endl;
		}
	}
	if (n > 1)cout << n << ' ' << 1 << endl;
}

3. Number of sieves

(1) Ordinary sieve method O(nlogn)

Both prime and composite numbers are used to sift out the multiples behind them

void get_primes(int n)
{
	for (int i = 2; i <= n; i++)
	{
		if (!st[i])primes[cnt++] = i;
		for (int j = i; j <= n; j += i)st[j] = true;
	}
}

(2) Angstrom sieve method O(nloglogn)

The principle of Eratosthenes sieve method is that the multiples of any integer x, 2x, 3x,... Are not prime numbers.
However, even so, there will be repeated marking. For example, 12 will be marked by both 2 and 3. When marking the multiple of 2, 12 = 6 * 2, and when marking the multiple of 3, 12 = 4 * 3. The fundamental reason is that there is no unique way to produce 12.

void get_primes(int n)
{
	for (int i = 2; i <= n; i++)
	{
		if (!st[i])
		{
			primes[cnt++] = i;
			for (int j = i; j <= n; j += i)st[j] = true;
		}
	}
}

(3) Linear sieve method O(n)

n will only be sifted out by his smallest prime factor
If i%primes[j]==0, it means that primes[j] is the minimum prime factor of i and also the minimum prime factor of primes[j]*i. therefore, in order to prevent repeated marking, break can be used

void get_primes(int n)
{
	for (int i = 2; i <= n; i++)
	{
		if (!st[i])primse[cnt++] = i;
		for (int j = 0; primes[j] <= n / i; j++)
		{
			st[primes[j] * i] = true;
			if (i % primes[j] == 0)break;
		}
	}
}

4. Goldbach conjecture

Any even number greater than 4 can be split into the sum of two odd primes.
Directly enumerate the prime numbers

		for (int i = 1;; i++)
		{
			int a = primes[i];
			int b = n - a;
			if (!st[b])
			{
				printf("%d = %d + %d\n", n, a, b);
				break;
			}
		}

5. Factorial decomposition

Example: if you calculate 8! Number of 2 in

1 2 3 4 5 6 7 8
  1   1   1   1
      1       1
              1
 4 + 2 + 1 = 7
    for (int i = 0; i < cnt; i++)
    {
        int p = primes[i];
        int s = 0;
        for (int j = n; j; j /= p)s += j / p;
        cout << p << ' ' << s << endl;
    }

II Counting

Quick power template:

int qmi(int a, int k)
{
    int res = 1;
    while (k)
    {
        if (k & 1)res = (LL)res * a % mod;
        a = (LL)a * a % mod;
        k >>= 1;
    }
    return res;
}

III Divisor

1. Try division to find the divisor

Paired sieve

vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}

2. Approximate number

(1) Approximate number template

Conclusion: n=p1^a1 * p2^a2 * p3^a3
ans=(a1+1) * (a2+1) * (a3+1)....
Each divisor d can be expressed as
d=p1^b1 * p2^b2 * p3^b3...
There are 0 ~ a1 selection methods in b1 and 0 ~ a2 selection methods in b2
So the approximate number is (a1+1) * (a2+1) * (a3+1)
Please n^ How many divisors are there altogether
(2c1+1)∗(2c2+1)∗...∗(2ck+1)

void divisor(int n)
{
	unordered_map<int, int> hash;
	for (int i = 2; i <= n / i; i++)
	{
		while (n % i == 0)
		{
			n /= i;
			hash[i]++;
		}
	}
	if (n > 1)hash[n]++;
	int res = 1;
	for (auto& x : hash)ans *= (x.second + 1) % mod;
	cout << res << endl;
}

(2). Ingenious conversion of divisor and multiple

Divisor and multiple are actually a pair of good friends. When the time of finding divisor is too complex, you might as well consider solving the problem from the perspective of multiple
Example: for each Ai, how many numbers in other numbers are its divisor?
Count the number of Ai occurrences

   for(int i = 0; i < n; i++) 
    {
        scanf("%d", &a[i]);
        cnt[a[i]]++;
    }
   for(int i = 1; i < N; i++)
    {
        if(!cnt[i]) continue;
        //i is actually Ak, and j is a multiple of i
        for(int j = i; j < N; j += i)
        {
            res[j] += cnt[i];
        }
    }
    Finally, for each res - 1(Delete yourself)

3. Sum of approximations


while (b – ) t = (t * a + 1) % mod;

t=t∗p+1
t=1
t=p+1
t=p^2+p+1
......
t=p^b + p^b-1...+1

void divisor(int n)
{
	unordered_map<int, int> hash;
	for (int i = 2; i <= n / i; i++)
	{
		while (n % i == 0)
		{
			n /= i;
			hash[i]++;
		}
	}
	if (n > 1)hash[n]++;
	int res = 1;
	for (auto x : hash)
	{
		long long t = 1;
		while (x.second--)t = (t * x.first + 1) % mod;
		res = res * t % mod;
	}
	cout << res << endl;
}

4. Inverse prime

Topics: C++ Algorithm