专栏文章

P2613 【模板】有理数取余 讲解

P2613题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@miq04e77
此快照首次捕获于
2025/12/03 20:46
3 个月前
此快照最后确认于
2025/12/03 20:46
3 个月前
查看原文

声明:

在接下来的讲述中,我会用 pp 代表题中的模数 1926081719260817

前置芝士:

  • 快读;
  • 逆元;
  • 扩展欧几里得。

正解:

  • 读入:
    很显然,这道题输入的数太大了,根本不能用正常的方法输入,用字符串行不行呢?太麻烦了。所以我们考虑在输入时对其取模。还记得快读吗?我们只需要加一个取余就行了。如:
    CPP
    inline int rd(){
        int x=0,ch=getchar();
        while(!isdigit(ch)&&ch!=EOF) ch=getchar();
        while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch-'0'),x%=mod,ch=getchar();
        return x;
    }
    
解决了读入,剩下的就很简单了。
首先把题目中的式子改一下,如:
c=ab c=\dfrac{a}{b}
c=ab1 c=ab^{-1}
将除以 bb 改为乘 bb 的逆元,即乘 b1b^{-1}。接下来就要看看逆元如何求了。这里我采用的是扩展欧几里得求逆元。
  • 扩欧求逆元:
    已知求逆元时,我们会写出一个同余方程:ax1(modb)ax \equiv 1 \pmod b,解出的 xx 即为 aa 在模 bb 意义下的逆元。在题中,用于求解 bb 在模 pp 意义下的逆元的方程是:bxa(modp)bx \equiv a \pmod p,那如何解这个方程呢?很简单,将其改造一下:
    bxa(modp)b x\equiv a \pmod p
    bxpy=ab x-p y=a
    由于 yy 可以是任何数,所以可以写成:
    bx+py=ab x+p y=a
    转化为熟悉的样子:
    bx+py=gcd(b,p)b x+p y=\gcd(b,p)
    求解过程:
    设:
    bx1+py1=gcd(b,p)b x_1+p y_1 = \gcd(b,p)
    px2+(bmodp)y2=gcd(p,bmodp)p x_2 + (b \bmod p)y_2 =\gcd(p,b \bmod p)
    gcd(b,p)=gcd(p,bmodp)\because \gcd(b,p) = \gcd(p,b \bmod p)
    bx1+py1=px2+(bmodp)y2\therefore b x_1+p y_1 = p x_2 + (b \bmod p)y_2
    bmodp=b(bp×p) \because b \bmod p = b - ( \left\lfloor \frac{b}{p} \right \rfloor \times p)
    bx1+py1=px2+(b(bp×p))y2\therefore b x_1+p y_1 = p x_2 + (b - ( \left\lfloor \frac{b}{p} \right \rfloor \times p))y_2
    bx1+py1=by2+px2bp×py2b x_1 + p y_1 = b y_2 + p x_2 - \left\lfloor \frac{b}{p} \right \rfloor \times p y_2
    bx1+py1=by2+p(x2bp×y2) b x_1 + p y_1 = b y_2 + p (x_2 - \left\lfloor \frac{b}{p} \right \rfloor \times y_2)
    b=b,p=p\because b=b,p=p
    x1=y2,y1=x2bp×y2\therefore x_1=y_2,y_1=x_2 - \left\lfloor \frac{b}{p} \right \rfloor \times y_2
    x2x_2y2y_2 不断代入递归求解,直至 gcd\gcd00,递归 x=1,y=0x=1,y=0 回去求解。
    像这样求出来的 xx 就是 bb 在模 pp 意义下的逆元了。
    最后用 aaxx 再取模就行了。

代码:

CPP
#include<bits/stdc++.h>
#define inl inline
#define reg register
#define int long long
#define rep(i,x,y) for(reg int i=x;i<=(y);++i)
#define per(i,x,y) for(reg int i=x;i>=(y);--i)
using namespace std;
const int p=19260817;
inline int rd(){
    int x=0,ch=getchar();
    while(!isdigit(ch)&&ch!=EOF) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch-'0'),x%=p,ch=getchar();
    return x;
}
int a,b,x,y;
void exgcd(int a,int b){
    if(b==0){
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);
    int t=x;
    x=y;
    y=t-(a/b)*y;
}
signed main(){
	a=rd();
    b=rd();
    if(b==0){  //分母不能为 0,故无解。
        cout<<"Angry!";
        return 0;
    }
    exgcd(b,p);
    x=(x%p+p)%p; //保证为正数
    cout<<a*x%p;
	return 0;
}

评论

3 条评论,欢迎与作者交流。

正在加载评论...