YbtOJ 「数学基础」 第2章 质数和约数

质数和约数

线性筛

void getprime ( int lim )
{
	for ( int i = 2 ; i <= lim ; i ++ )
	{
		if ( !isntprime[i] ) prime[++cnt] = i;
		for ( int j = 1 ; j <= cnt && i * prime[j] <= lim ; j ++ )
		{
			isntprime[i*prime[j]] = 1;
			if ( i % prime[j] == 0 ) break; 
		}
	}
}


算术基本定理

正整数\(n\)可以唯一分解成有限个质数的乘积\(n=p_1^{c_1}+p_2^{c_2}+\dots +p_m^{c_m}\) 其中\(c_i\)都是正整数

算术基本定理的推论

正整数\(n\)的正约数个数:\((c_1 + 1) * (c_2 + 1) * ... * (c_m + 1) = \prod_{i=1}^{m}(c_i + 1)\) 其中加的\(1\)表示质数\(p_i\)\(0\)次方

最大公约数和最小公倍数

#include <bits/stdc++.h>
using namespace std;
int gcd ( int a , int b )
{
	if ( a % b == 0 ) return b;
	else return gcd ( b , a % b );
}
int main()
{
	int a , b;
	scanf ( "%d%d" , &a , &b );
	printf ( "%d\n" , gcd ( a , b ) );//最大公约数
	printf ( "%d\n" , a * b / gcd ( a , b ) ); //最小公倍数 
	return 0;
}

A. 【例题 1】线性筛素数

线性筛板子题

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

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 , q;

int prime[N] , isntprime[N] , cnt;

void getprime ( int lim )
{
    for ( int i = 2 ; i <= lim ; i ++ )
    {
        if ( !isntprime[i] ) prime[++cnt] = i;
        for ( int j = 1 ; j <= cnt && i * prime[j] <= lim ; j ++ )
        {
            isntprime[i*prime[j]] = 1;
            if ( i % prime[j] == 0 ) break; 
        }
    }
}

signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    n = read() , q = read(); getprime(n);
    for ( int i = 1 ; i <= q ; i ++ ) cout << prime[read()] << endl;
    return 0;
}

B. 【例题2】质数距离

显然对于任意一个合数\(n\) 它一定有一个不超过\(\sqrt n\)的质因子 所以对于一个质数\(p\) \(i*p\)就是一个合数 所以我们可以预先处理出\([2,\sqrt R]\)的的所有质数

再通过这些质数去筛出\([L,R]\)之间的所有合数 而区间内没有被筛到的就是质数

注意循环条件需要严格保证 \(j*prime[i]\)覆盖了\([l,r]\)区间内的所有值 如果直接\(l/prime[i]\)的话 有可能会下取整 导致\(j\)的下界变大 覆盖范围变大导致出错

#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
const int N = 1e7 + 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 n , q;

int prime[N] , isntprime[N] , cnt;

void getprime ( int lim )
{
	for ( int i = 2 ; i <= lim ; i ++ )
	{
		if ( !isntprime[i] ) prime[++cnt] = i;
		for ( int j = 1 ; j <= cnt && i * prime[j] <= lim ; j ++ )
		{
			isntprime[i*prime[j]] = 1;
			if ( i % prime[j] == 0 ) break; 
		}
	}
}

int l , r , num[N] , cntt;

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	getprime((int)sqrt(2147483647));
	while ( cin >> l >> r )
	{
		memset ( isntprime , 0 , sizeof isntprime );
		cntt = 0;
		if ( l == 1 ) l ++;
		for ( int i = 1 ; i <= cnt ; i ++ )
			for ( int j = ( l - 1 ) / prime[i] + 1 ; j <= r / prime[i] ; j ++ )
				if ( j > 1 ) isntprime[j*prime[i]-l] = 1;
		for ( int i = l ; i <= r ; i ++ ) if ( !isntprime[i-l] ) num[++cntt] = i;
		if ( cntt < 2 ) cout << "There are no adjacent primes." << endl;
		else 
		{
			int maxx1 = num[1] , maxx2 = num[2] , maxx = num[2] - num[1];
			int minn1 = num[1] , minn2 = num[2] , minn = num[2] - num[1];
			for ( int i = 3 ; i <= cntt ; i ++ )
			{
				if ( num[i] - num[i-1] > maxx ) maxx = num[i] - num[i-1] , maxx1 = num[i-1] , maxx2 = num[i];
				if ( num[i] - num[i-1] < minn ) minn = num[i] - num[i-1] , minn1 = num[i-1] , minn2 = num[i];
			}
			cout << minn1 << ',' << minn2 << " are closest, " << maxx1 << ',' << maxx2 << " are most distant." << endl;
		}
		
	}
	return 0;
}

C. 【例题3】不定方程

\(y=\frac {xn!} {x-n!}\) 那么我们设\(t=x-n!\) 那么\(x=t+n!\) 得到\(y=n!+\frac{{(n!)}^2}{t}\)

因为\(n\)\(y\)都是整数 所以\(t\)一定是\({(n!)}^2\)的约数

我们知道对于一个合数\(n\)的约数个数是\(\prod_{i=1}^m (c_i+1)\)

那么\(n^2\)的约数个数就是\(\prod_{i=1}^m (c_i*2+1)\) (因为去掉了\(n*n\)计算了两次的情况)

解的个数就是\(t\)的个数

那么对于阶乘来说 \(c\)的求法如下

所有质数都是\(n!\)的质因子 那么这个质数的一次方 二次方或者多次方(在n的范围内)的出现次数之和就是质数\(prime[i]\)的出现次数

#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;
}

int n , cnt , prime[5800001];
bool isntprime[N];

void getprime ( int lim )
{
	for ( int i = 2 ; i <= lim ; i ++ )
	{
		if ( !isntprime[i] ) prime[++cnt] = i;
		for ( int j = 1 ; j <= cnt && i * prime[j] <= lim ; j ++ )
		{
			isntprime[i*prime[j]] = 1;
			if ( i % prime[j] == 0 ) break; 
		}
	}
}

int c[N];

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	n = read(); getprime(n);
	for ( int i = 1 ; i <= cnt ; i ++ )
		for ( int j = prime[i] ; j <= n ; j *= prime[i] )
			c[i] += n / j , c[i] %= mod;
	int ans = 1;
	for ( int i = 1 ; i <= cnt ; i ++ ) ans = ( ans * ( c[i] * 2 + 1 ) ) % mod;
	cout << ans;
	return 0;
}
posted @ 2023-06-22 09:50  Echo_Long  阅读(36)  评论(0编辑  收藏  举报