P2613 【模板】有理数取余(逆元求除法的模+费马小定理/扩展欧几里得)
题目描述:
给出一个有理数 c=a/b,求 c mod 19260817 的值。
思路:求b关于mod的逆元k,得(k*b)%m=1,(a/b)mod m=
((a/b)%m)*(k*b%m)=a*k%mod,a,b的数值很大,需要在读数
的时候用快读模板对m求余先,逆元这题除了
扩展欧几里得:
void extend_gcd(ll a, ll b, ll& x, ll& y) { if (b == 0) { x = 1, y = 0; return; } extend_gcd(b, a % b, x, y); ll tmp = x; x = y; y = tmp - (a / b) * y; } ll mod_rev(ll a, ll m) { ll x, y; extend_gcd(a, m, x, y); return (m + x % m) % m; }
这题因为m是素数,与a互素,可以用费马小定理,
a^(m-1)≡1(mod m),则a'=pow(a,m-2);
ll qpow(ll a, ll n) { ll ans = 1; while (n) { if (n & 1) { ans = (ans * a) % mod; } a = (a * a) % mod; n >>= 1; } return ans; } ll mod_rev2(ll a, ll m) { return qpow(a, m - 2); }
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 10000005; const int inf = 0x3f3f3f3f; const int mod = 19260817; void read(ll& sum) { sum = 0; char p = getchar(); for (; !isdigit(p); p = getchar()); for (; isdigit(p); p = getchar()) { sum = sum * 10 % mod + p - '0'; } sum% mod; } void extend_gcd(ll a, ll b, ll& x, ll& y) { if (b == 0) { x = 1, y = 0; return; } extend_gcd(b, a % b, x, y); ll tmp = x; x = y; y = tmp - (a / b) * y; } ll mod_rev(ll a, ll m) { ll x, y; extend_gcd(a, m, x, y); return (m + x % m) % m; } ll qpow(ll a, ll n) { ll ans = 1; while (n) { if (n & 1) { ans = (ans * a) % mod; } a = (a * a) % mod; n >>= 1; } return ans; } ll mod_rev2(ll a, ll m) { return qpow(a, m - 2); } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } int main() { //freopen("test.txt", "r", stdin); ll a, b; read(a);//大数需要对m求余 read(b); if (gcd(b, 19260817) != 1) { printf("Angry!\n"); return 0; } printf("%lld\n", a * mod_rev2(b, 19260817) % 19260817); return 0; }