• 【笔记】很基础的数论知识


    2020.1.17 qbxt笔记

    最大公约数、最小公倍数

    定义

    如果d是能同时整除a, b中最大的正整数,我们称d为a和b的最大公约数,记作d = gcd(a, b)

    如果一个数d,既是a的倍数,又是b的倍数,同时d是满足这两个条件中的最小正整数,那么称d是a和b的最小公倍数,记作d =
    lcm(a, b)

    辗转相除法

    •假设a > b,我们有gcd(a, b) = gcd(b, a % b)

    利用这样的方法,可以把求最大公约数的问题转化为两个更小的数的最大公约数,从而完成求解

    时间复杂度为log

    求得$ gcd(a,b)$之后我们就很容易求出a与b的最小公倍数

    $ gcd(a,b) * lcm(a, b) = a * b $

    int gcd(int a,int b){
    	return b==0?a:gcd(b,a%b); 
    }
    

    唯一分解定理

    任意一个正整数x,都可以唯一地分解成p1^a1 * p2^a2 * … * pn^an的形式,其中p1到pn是素数(不考虑素数之间的顺序)

    时间复杂度为O(log x)

    例题

    1.NOIP2001 最大公约数和最小公倍数问题

    传送

    输入两个正整数x, y,问有多少对正整数以x为最大公约数,以y为最小公倍数

    x <= 10^5, y <= 10^6

    上面我们刚刚提到,$ gcd(a,b) * lcm(a, b) = a * b $

    所以我们可以知道x ,y的乘积,只需要枚举x,便可以知道y。

    并判断x和y是否满足题意中最大公约数为x,最小公倍数为y

    统计满足的x和y的数量即为所求答案

    #include<iostream>
    #include<math.h>
    #include<cstdio>
    using namespace std;
    int x,y;
    int gcd(int a,int b){
    	return b==0?a:gcd(b,a%b); 
    }
    int ans;
    int main(){
    	scanf("%d%d",&x,&y);//最大公约数 最小公倍数 x*y=p*q;
    	for(int i=1;i<=sqrt(x*y);i++){
    		if((x*y)%i==0){
    			if(gcd(i,(x*y)/i)==x)ans++;
    		}
    	} 
    	cout<<ans*2;
    }
    

    2.比例化简

    多啦a梦的任意门(滑稽

    我们发现L的范围很小,最大直到100。考虑我们枚举答案的分子分母,判断互质。并使A’/B’≥ A/B且A’/B’- A/B的值尽可能小。

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	float a,b,c;
    	cin>>a>>b>>c;
    	float ansmin=100,ansa,ansb,sum;
    	//cout<<a/b;
    	for(float i=1;i<=c;i++){
    		for(float j=1;j<=c;j++){
    			if(i/j>=a/b){
    				sum=i/j-a/b;
    				if(sum<ansmin){
    					ansa=i,ansb=j;
    					ansmin=sum;
    				}	
    			}	
    			//cout<<sum<<" "<<ansmin<<endl;	
    		}
    	}
    	cout<<ansa<<" "<<ansb<<endl;
    }
    

    嗯对啦,上面的写法在luogu上能通过,但还存在精度上的问题

    我们还可以模拟一下分数的运算过程

    ll gcd(ll a,ll b){
    		return b == 0 ? a : gcd(b,a % b);
    }
    struct frac{
    		ll a,b;
    };
    frac operator +(frac x,frac y){
    	ll n = x.a * y.b + x.b * y.a;
      	ll m = x.b * y.b;
      	ll z = gcd(m,n);
      	n /= z,m /= z;
      	return (frac){n,m};
    }
    bool operator <(frac x,frac y){
    		return x.a * y.b < x.b * y.a;
    }
    

    补充的一些内容

    整数

    int 范围是-231-1~231-1

    long long 范围是-263-1~263-1

    unsigned int 范围是0~2^32-1

    unsigned long long 范围是0~2^64-1

    进制

    P进制下的(a1,a2,…an)代表的数字是

    (a 1 * p^{(n-1)} + a 2 * p^{(n-2)} + … + an)

    嗯对,剩下内容自己看初赛一本通吧(滑稽x

    高精度

    cyc最爱的高精度

    高精度的加减乘法都是挺简单x

    至于除法emm(应该也没人会考吧qwq??

    但还是补充一下吧

    高精度除以低精度

    bignum operator/(bignum x,bignum y){
        bignum z;
        z.len = x.len;
        for(int i=z.len;i;i--)
        {
            z.a[i]=x.a[i]/y;
            x.a[i-1]+=10*x.a[i]%y;
        }
        while(z.len>1&&z.a[z.len] == 0)z.len--;
        return z;
    }
    

    高精度除以高精度

    ……我 我算了我放弃了我太难了(以下是代码

    bool operator<=(Bignum x,Bignum y)
    {
    	if(x.len<y.len)return 1;
    	if(x.len>y.len)return 0;
    	for(int i=x.len;i;i--)
    	if(x.a[i]!=y.a[i])
    	return x.a[i]<=y.a[i];
    	return 1;
    }
    Bignum shift(Bignum x,int len)
    {
    	Bignum y;
    	y.len=x.len+len;
    	for(int i=1;i<=x.len;i++)
    	y.a[i+len]=x.a[i];
    	return y;
    }
    Bignum operator/(Bignum x,Bignum y)
    {
    	Bignum z;
    	z.len=x.len;
    	for(int i=z.len;i;i--)
    	{
    		for(int k=9;k>0;k--)
    		if(shift(y,i-1)*k<=x)
    		{
    			z.a[i]=k;
    			x=x-shift(y,i-1)*Bignum(k);
    			break;
    		}
    	}
    	while(z.len>1&&z.a[z.len]==0)z.len--;
    	return z;
    }
    

    压位

    一个int只存储0到9的数字位,使得我们的程序空间和时间效率都不高

    int的最大范围可以达到2147483647,所以一个int存储8位是没问题的

    在读入和输出的时候要注意,除了最高位之外要补0

    进制转换

    假设从p进制转换到q进制

    如果一个long long能存下:先转换到10进制再转换到q进制

    如果一个long long不能存下:模拟除法除q的过程

    同余

    同余使我秃头。

    如果a和b模m之后的数值是相等的,那么a和b模m同余

    OI里很多题目需要取模,需要用同余的结论

    •同余是模意义下的等价关系

    •很多运算在同余意义下也存在等价的运算

    •除法(等价于乘以逆元)

    •开根号(等价于求模方程的根)

    •对数(等价于离散对数)

    逆元

    •在模意义下,一个相当于1/a的数

    •记a的逆元为a^-1

    •逆元满足a * a^-1 = a^-1 * a = 1 (mod p)

    •需要掌握模质数的逆元

    费马小定理

    •a^(p-1) = 1 (mod p)

    •所以逆元就是a^(p-2)

    •使用快速幂就可以了

    扩展欧几里得定理

    https://www.cnblogs.com/huixinxinw/p/12207417.html

  • 相关阅读:
    导入模块
    Windows x86-64下python的三个版本
    ubuntu 16.04 添加网卡
    重启rsyncd
    docker时区
    git回滚
    impdp and docker install oracleXE
    Oracle 把一个用户所有表的读权限授予另一个用户
    zabbix web监控
    WebStorm license server
  • 原文地址:https://www.cnblogs.com/huixinxinw/p/12207433.html
Copyright © 2020-2023  润新知