有理数取余

1.辗转相除法(求a,b的公约数)

摘要:

gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0)

a可以表示成a = kb + r(a,b,k,r皆为正整数,且r<b),则r = a mod b
假设d是a,b的一个公约数,记作d|a,d|b,即a和b都可以被d整除。
而r = a - kb,两边同时除以d,r/d=a/d(整数)-kb/d(整数)=m,由等式右边可知m为整数。
因此d也是b,a mod b的公约数
因(a,b)和(b,a mod b)的公约数是一样的,则其最大公约数也必然相等,得证。
证明

注:a/b = 整数            -》          b为a的因数

疑问:a/b = k(整数),k<0上面一条是否同样成立?

 

过渡:辗转相除法是一个铺垫,之后的有理数取余求逆元会用到这个

 

2.有除法的取余!!!

假设我们已经算出了:

ans = (a * b * c) % p;
现在要从 ans 中把 b 给除掉,如何处理 ans?

如果像下面这样直接除会出错(举个实例会很直观)
问题

 

求这样一个满足 ax mod b = 1的 x 有什么用呢?一个重要用途如下。

这个 x 就是: a 在模 b 意义下的乘法逆元。

在模 b 意义下,如果想要除以 a 就非常麻烦。这时候乘以 a 的逆元等效于除以 a。
解决方法

 

原理可以这么理解:

abcx ≡ ac (bx) ≡ ac (modp)
原理解释

 

#include<bits/stdc++.h>
using namespace std;

long long x, y;//目前方程真正的解 

void exgcd(long long a, long long b)
{
    //当前目的:求解 ax + by = gcd(a, b) 这么一个方程

    if(b == 0) //a, b不断改变的过程中,b最终必然会成为0
    {
        //在 b = 0 时方程还要成立? 使 x = 1, y = 0 ,必然成立 
        x = 1;
        y = 7; //建议返回0。不过y = 7能AC,证明了最后一个等式不受最后一个y影响
        return;
    } 

    exgcd(b, a % b);//把下一层系数传进去(先求下一个方程的解 )

    //现在我们已经拿到了下一个方程的解x, y
    long long tx = x;//暂时存一下x,别丢了
    x = y;
    y = tx - a / b * y; 
}

int main()
{
    long long a, b;
    cin >> a >> b;
    exgcd(a, b);

    x = (x % b + b) % b;//我们求出来的x必然满足方程,但不一定是最小正整数解,所以要进行答案处理
    printf("%lld\n", x);
    return 0;
}
View Code

 

 

3.扩展欧几里得算法:求逆元

a%p = x1;

ans = a*b;

ans/b%p = x2;

x1 != x2;

c是b的逆元

ans*b%p= x3;

x1 = x3;

 

4.有理数取余

有除法的取余不能随便取

#include<iostream>
#include<cstdio>
using namespace std;
const int mod = 19260817;
int input()
{
    int res = 0;
    char ch = getchar();
    while(ch>'9'||ch<'0')
    {
        if(ch=='-')
            res = -1;
        ch = getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        res = (res << 1) + (res << 3) + (ch - '0');
        res %= mod;
        ch = getchar();
    }
    return res;
}
int x, y;
void exgcd(int a, int b)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return ;
    }
    exgcd(b, a % b);
    int lastx = x;
    x = y;
    y = lastx - a / b * y;
}

int main()
{
    int a, b;
    a = input();
    b = input();
    //cout << a <<"  "<<b<<endl;
    if(b == 0)
    {
        cout <<"Angry!"<<endl;
        return 0;
    }
    exgcd(b, mod);
    x = (x % mod + mod) % mod;
    cout << 1LL*a*x%mod;
    return 0;
}
除数取余

 

 

5.对于很大大数字,在输入时就要取模

 

求这样一个满足 ax \mod b = 1axmodb=1 的 xx 有什么用呢?一个重要用途如下。

这个 xx 就是: aa 在模 bb 意义下的乘法逆元。

在模 bb 意义下,如果想要除以 aa 就非常麻烦。这时候乘以 aa 的逆元等效于除以 aa

 

6、易错点:

a(很大所以%了k)-b((很大所以%了k)有可能为负数(本来a>b,a-b一定为正的)

解决办法:(a+k-b)%k;

例题(前两次交的代码就超级有问题)

 

7.对于ans = a^b这种超大类型的,如果要求ans % k,不能(a%k)^(b%k),但是可以使用快速幂pow(a, b, k)这种形式取模

posted @ 2021-02-02 21:57  bear_xin  阅读(304)  评论(0)    收藏  举报