C++ 数论知识总结

引言

数论大法好,人间真善美。。。


数论模板

一. 判定质数

二. 欧拉筛法

三. 欧拉函数

方法一

方法二

四. 二元一次不定方程

五. 矩阵乘法

六. 快速幂

七. 中国剩余定理

八. 中国剩余定理Pro

练习题




一. 判定质数

for(int i = 2 ; i * i <= n ; ++i) {
    if( n % i == 0 )
    {
        flag = 1 ;
        breke;
    }
}

二. 欧拉筛法

求  n 以内的质数

for(int i = 2 ; i <= n ; ++ i ) {
    if( ! vis[i] )
    {
        cnt ++ ;
        p[cnt] = i ;
    }
    for( int j = 1 ; j <= cnt && i * p[j] <= n ; ++ j )
    {
        vis[p[j] * i ] = 1 ;
        if( i % p[j] == 0 ) break;
    }
}

三. 欧拉函数

关于欧拉函数,求 n  以内与 n 互质数的个数

方法一

scanf("%lld", &n );
        if( n == 0 )
            return 0;
        long long m = n ;
        for(int i = 2 ; i * i <= m ; ++ i )//分解为质数乘积
        {
            if( m % i == 0 )
            {
                cnt ++ ;
                p[cnt] = i ;
                while( m % i == 0 )
                {
                    m = m / i ;
                    w[cnt] ++ ;
                } 
            }
        }
        if( m != 1 )
        {
            cnt ++ ;
            p[cnt] = m ;
            w[cnt] = 1 ;
        }
        long long ans = 1 ;
        for(int i = 1 ; i <= cnt ; ++ i )
        {
            ans = ans * (p[i] - 1 ) ;
            for(int j = 1 ; j < w[i] ; j ++ )
            {
                ans = ans *p[i] ;
            }
        }

方法二

ph[1] = 1 ;//结合欧式筛法,可以求出 n 以内每一个数的欧拉函数值
    scanf("%d", &n );
    for(int  i = 2 ; i <= n ; ++ i ) {
        if(!vis[i]) {
            cnt ++ ;
            pr[cnt] = i ;
            ph[i] = i - 1 ;
        }
        for(int j = 1 ; j <= cnt && i * pr[j] <= n ; ++ j ) {
            vis[ i * pr[j] ] = 1 ;
            if( i % pr[j] == 0 ) {
                ph[ pr[j] * i ] = ph[i] * pr[j] ;
                break;
            }
            else
                ph [ pr[j] * i] = ph[i] * (pr[j] - 1 );
        }
    }

​

四. 二元一次不定方程

关于求解二元一次不定方程

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
 
int a , b , c , T ;
 
int ex( int a , int b , int &x , int &y )
{
    if(  b == 0 )
    {
        x = 1 ;
        y = 0 ;
        return a; 
    }
    else
    {
        int u = ex( b , a % b , y , x );
        y -= x *( a/b );
        return u ;
    }
}
 
int main()
{
    scanf("%d", &T );
    for(int h = 1 ; h <= T ; ++ h )
    {
        scanf("%d%d%d", &a , &b ,&c );
        int x = 0 ,y  = 0 ;
        int p = ex( a, b , x , y );
        x = x * ( c / p );
        y = y * ( c / p );
        cout<<x << " "<< y <<endl; 
    }
}

五. 矩阵乘法

对于 n*m 的矩阵乘 m*q 的矩阵得到的矩阵为 n*q 的矩阵

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long 
using namespace std;
 
ll m , n , q ; 
ll c[107][107] , a[107][107] , b[107][107] ;
 
int main()
{
    scanf("%lld%lld", &n , & m );
    for(int i = 1 ; i <= n ; ++ i )
        for(int j = 1 ; j <= m ; ++ j )
            scanf("%lld", &a[i][j] );
    scanf("%lld", &q );
    for(int i = 1 ; i <= m ; ++ i )
        for(int j = 1 ; j <= q ; ++ j )
            scanf("%lld", &b[i][j] );
    for(int i = 1 ; i <= n ; ++ i )
        for(int j = 1 ; j <= q ; ++ j )
            for(int k = 1 ; k <= m ; ++ k )
                c[i][j] += a[i][k] * b[k][j] ;
    for(int i = 1 ; i <= n ; ++ i ) {
        for(int j = 1 ; j <= q ; ++ j ) {
            printf("%lld", c[i][j] );
            if( j != q )
                printf(" ");
        }
        printf("\n");
    }
    return 0;
}

最好用结构体表示矩阵,用构造函数

struct squr{
    ll n , m ;
    ll c[1007][1007] ;
    squr () {
        memset( c , 0 , sizeof( c ) );
    }
    squr operator *( const squr b ) {
        squr z;
        z.n = n , z.m = b.m ;
        for( int i = 1 ; i <= n ; ++ i ) 
            for(int j = 1 ; j <= z.m ; ++ j ) 
                for(int k = 1 ; k <= m ; ++ k ) 
                    z.c[i][j] = (z.c[i][j] + ( c[i][k] * b.c[k][j] % mod )) % mod ;
        return z ;
    } 
};

六. 快速幂

x 表示底数,y 是指数,求的是x^{y}

int quick_pow( int x , int y )
{
    int sum = 1 ;
    while( y > 0 ) {
        if( y % 2 )
            sum = sum * x % mod ;
        y /= 2;
        x = x * x % mod ;
    }
    return sum;
}

七. 中国剩余定理

概念(简化版)

证明(详细)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
 
int a[1007] , m[1007] ;
int n , ans , M =1 ; 
 
int exgcd( int a , int b , int &x , int &y ) //扩展欧几里得
{
	if( b ==0 ) {
		x = 1;
		y = 0;
		return a;
	}
	else {
		int u = exgcd( b , a%b , y , x );
		y -= (a/b)*x ;
		return u;
	}
}
 
void China()
{
	for(int i = 1 ; i <= n ; ++ i ) {
		int temp = M / a[i] ;
		int x , y ;
		int gcd = exgcd( temp , a[i] , x , y );
		x = (x%a[i]+a[i])%a[i] ;
		ans = (ans + temp*x*m[i] ) % M ;
	}
}
 
int main()
{
	
	scanf("%d", &n );
	for(int i =1 ; i <= n ; ++ i ) {
		scanf("%d%d", &a[i] , &m[i] );
		M *= a[i] ;//最小公倍数
	}
	China();
	printf("%d", (ans%M+M) % M );
	return 0;
}


八. 中国剩余定理Pro

暂时只给出代码。。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long 
#define N 100005 
using namespace std;

ll n ;

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

ll exCRT() {
	ll a1 , m1 ;
	n -- ;
	bool flag = 0 ;
	scanf("%lld%lld", &a1 , &m1 );
	while( n -- ) {
		ll a2 , m2 , dis ;
		scanf("%lld%lld", &a2 , &m2 );
		dis = m1-m2 ;
		ll x , y , u , lcm ;
		u = exgcd( a1 , a2 , x , y );
		if( dis%u )
			flag = 1 ;
		x = dis/u*x%a2 ;
		m1 -= a1*x ;
		a1 = a1/u*a2 ;
		m1 %= a1 ;
	} 
	if( flag )
		return -1 ;
	else return (m1%a1+a1)%a1 ;
}

int main() {
	while( scanf("%lld", &n ) != EOF )
		printf("%lld\n", exCRT() );
} 


方便以后复习,查漏补缺


练习题

1. 计算系数

2. 求n以内互质数的个数

3. gcd(数论)

4. 迷路

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值