【普及+/提高】洛谷P2613 ——【模板】有理数取余
见:P2613 【模板】有理数取余 - 洛谷
题目描述
给出一个有理数 c=ba,求 cmod19260817 的值。
这个值被定义为 bx≡a(mod19260817) 的解。
输入格式
一共两行。
第一行,一个整数 a。
第二行,一个整数 b。
输出格式
一个整数,代表求余后的结果。如果无解,输出 Angry!
。
输入输出样例
in:
233
666
out:
18595654
说明/提示
对于所有数据,保证 0≤a≤1010001,1≤b≤1010001,且 a,b 不同时是 19260817 的倍数。
算法介绍
本题需使用逆元。
逆元即对于同余方程 ax≡1(modp),
则 x 为 amodp 的逆元,
记作 a−1。
若其满足 a∤p,
则 a−1≡ap−2(modp)。
本题中 a 和 b 为较大的整数,
可以用快读来读入,
并对 19260817 取模。
正确性证明
根据费马小定理可知 ap−1≡1(modp)。
费马小定理证明:
构造集合 S={1,2,3,…,p−1},
同时构造集合 S′={a,a×2,a×3,…,a×(p−1)}。
由于 a∤p,
所以 a 和 p 互质。
因此对于所有不同的 u 和 v,
一定满足 a×u≡a×v(modp)。
所以 S′ 是模 p 意义下的完全剩余系,
且没给元素都与 S 中的某个元素同余。
然后计算 S 的积 ∏S=1×2×3×…(p−1)=(p−1)!(modp),
以及 S′ 的积 ∏S′=a×(a×2)×(a×3)×…(a×(p−1))=ap−1×(p−1)!(modp)。
因为 S 和 S′ 都是模 p 意义下的完全剩余系,
所以两集合的积同余,即 (p−1)!≡ap−1×(p−1)!(modp)。
最后化简得 ap−1≡1(modp)。
证出费马小定理,可以推出逆元式子:
1≡1(modp)a1×a−1≡ap−1(modp)a−1≡ap−2(modp)
对于幂的计算,可以使用快速幂。
时间复杂度 O(logA)。
此题还要用快读
由于 a/b 可能是超大整数(如 10^10000 量级),
需在读入时直接对 19260817 取模,
避免高精度计算。
因此,
需要改造传统的快读为“即时取模”的快读。
“即时取模”的快读是一种在输入大整数时直接进行取模运算的优化技术,
常用于处理需要大数运算但最终结果需取模的场景(如数论题目)。
其核心思想是在逐位读取数字时同步计算模值,
避免存储完整的大数。
“即时取模”的快读代码如下所示。
int read() {int x=0,f=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}while(c>='0' && c<='9') {x=(x*10LL+c-'0')%m;c=getchar();}return x*f;
}
代码实现
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int m=19260817;int read() {int x=0,f=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}while(c>='0' && c<='9') {x=(x*10LL+c-'0')%m;c=getchar();}return x*f;
}
ll fast(ll a,ll n,ll p) {ll s=1;while(n) {if(n&1)s=s*a%p;n>>=1;a=a*a%p;}return s%p;
}
int main() {ll a=read(),b=read();if(b==0)cout<<"Angry!";else cout<<a*fast(b,m-2,m)%m;return 0;
}
各位大佬
鼓励一下
关注+收藏+点赞
好吗