【模板】有理数取余(快速幂,费马定理 或 扩展欧几里得算法)
题目描述
给出一个有理数 c = a b c=\frac{a}{b} c=ba,求 c m o d 19260817 c \bmod 19260817 cmod19260817 的值。
这个值被定义为 b x ≡ a ( m o d 19260817 ) bx\equiv a\pmod{19260817} bx≡a(mod19260817) 的解。
输入格式
一共两行。
第一行,一个整数
a
a
a。
第二行,一个整数
b
b
b。
输出格式
一个整数,代表求余后的结果。如果无解,输出 Angry!
。
样例 #1
样例输入 #1
233
666
样例输出 #1
18595654
提示说明
特别注意: b ∗ x ≡ 1 ( m o d p ) b*x\equiv 1\pmod{p} b∗x≡1(modp) (只对于p是质数)
由费马定理得: b p − 1 ≡ 1 ( m o d p ) b^{p-1}\equiv 1\pmod{p} bp−1≡1(modp)(p为质数)
即: b ∗ b p − 2 ≡ 1 ( m o d p ) b*b^{p-2}\equiv 1\pmod{p} b∗bp−2≡1(modp)
得: x = b p − 2 ( m o d p ) x = b^{p-2} \pmod{p} x=bp−2(modp);
对于所有数据,保证 0 ≤ a ≤ 1 0 10001 0\leq a \leq 10^{10001} 0≤a≤1010001, 1 ≤ b ≤ 1 0 10001 1 \leq b \leq 10^{10001} 1≤b≤1010001,且 a , b a, b a,b 不同时是 19260817 19260817 19260817 的倍数。
代码内容
- 快速幂,费马定理
// #include <iostream>
// #include <algorithm>
// #include <cstring>
// #include <stack>//栈
// #include <deque>//队列
// #include <queue>//堆/优先队列
// #include <map>//映射
// #include <unordered_map>//哈希表
// #include <vector>//容器,存数组的数,表数组的长度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p=19260817;
//快读(分字符读入)
ll getint()
{
ll res=0,ch=getchar();
while(!isdigit(ch)&&ch!=EOF)
ch=getchar();
while(isdigit(ch))
{
res=(res<<3)+(res<<1)+(ch-'0');
res%=p;//取模p;
ch=getchar();
}
return res;
}
ll qmi(ll a,ll b,ll p)
{
//当b = 0,p = 1时
//①不 % p ,结果是 1
//② % p ,结果是 0(正确答案)
ll res=1%p;//注意:5 0 1
while(b)
{
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;//右移 1 位
}
return res;
}
int main()
{
ll a,b;//快读(分字符读入)
a=getint();
b=getint();
if(!b)
{
cout<<""<<endl;
return 0;
}
//b * x ≡ 1 (mod p)//乘法逆元
//b^{p-1} ≡ 1 (mod p)//费马定理
//b * b^{p-2} ≡ 1 (mod p)
//(b*x)模 p 余 1
//x = b^{p-2} (mod p);
//res = x
//(p 为质数,即 a 与模数 p 互质)
ll res=a*qmi(b,p-2,p);
//非负整数
cout<<(res%p+p)%p<<endl;
return 0;
}
- 扩展欧几里得算法
// #include <iostream>
// #include <algorithm>
// #include <cstring>
// #include <stack>//栈
// #include <deque>//队列
// #include <queue>//堆/优先队列
// #include <map>//映射
// #include <unordered_map>//哈希表
// #include <vector>//容器,存数组的数,表数组的长度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p=19260817;
//快读(分字符读入)
ll getint()
{
ll res=0,ch=getchar();
while(!isdigit(ch)&&ch!=EOF)
ch=getchar();
while(isdigit(ch))
{
res=(res<<3)+(res<<1)+(ch-'0');
res%=p;//取模p;
ch=getchar();
}
return res;
}
//扩展欧几里得算法(裴蜀定理)
//根据费马定理,任意正整数a, b都存在整数x, y
//使得ax + by = gcd(a, b)
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main()
{
ll a,b;//快读(分字符读入)
a=getint();
b=getint();
if(!b)
{
cout<<""<<endl;
return 0;
}
ll x,y;
//扩展欧几里得算法
//b*x≡1(mod p)
//b*x=p*y+1
/*b*x+p*y=1*/
exgcd(b,p,x,y);
//(p 为质数,即 a 与模数 p 互质)
//ax + by = gcd(a, b) = d = 1
//ll res=a*x*(1/d)=a*x
ll res=a*x;
//非负整数
cout<<(res%p+p)%p<<endl;
return 0;
}