数论专题
持续更新
A - 乘法逆元
求 \(1∼n\) 中的所有数在模 \(p\) 意义下的乘法逆元
1.快速幂
根据欧拉定理,若\(a\)和\(p\)互质,则\(a^{\varphi(p)}\equiv1\;(mod\;p)\),当\(p\)是质数,则满足:
\(p\) 为质数, \(a\) 为正整数, \(a\) 和 \(p\) 互质, 则\(a^{p-1} \equiv 1\;(mod\;p)\).
根据费马小定理: \(a \times a^{p-2} \equiv 1\;(mod \; p)\), \(a^{p-2}\;(mod\;p)\)即为\(a\)的逆元, 利用快速幂求解即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, p;
int pow_mod(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
b >>= 1;
}
return res;
}
int main()
{
scanf("%d%d", &n, &p);
for(int i = 1; i <= n; ++ i)
printf("%d\n", pow_mod(i, p - 2, p));
return 0;
}
2.扩展欧几里得
当\(a\)和\(p\)互质,但\(p\)不是质数时,解线性同余方程\(a*x\equiv1\;(mod\;p)\):
转化为:\(a*x+p*y\equiv1\),因为\(a\)和\(p\)互质,所以一定有解,用exgcd求解即可
exgcd解出的逆元有可能是负数,转化成\(mod\;p\)意义下的正数即可
#include <bits/stdc++.h>
using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
int n, p;
scanf("%d%d", &n, &p);
for(int i = 1; i <= n; ++ i)
{
int x, y;
exgcd(i, p, x, y);
x = (x % p + p) % p;
printf("%d\n", x);
}
return 0;
}
3.线性递推
设\(p = k * i + r\), \(k\)是\(\dfrac{p}{i}\)的商,\(r\)是余数
\(k*i+r\equiv0\;(mod\;p)\), 两边同时乘上\(i^{-1}\)和\(r^{-1}\)
\(k * r^{-1} + i^{-1} \equiv 0\;(mod\;p)\)
\(i^{-1} \equiv -k * r^{-1}\;(mod\;p)\)
\(i^{-1} \equiv -\left\lfloor\dfrac{p}{i}\right\rfloor * (p\;mod\;i)^{-1}\;(mod\;p)\)
且已知\(1^{-1}\equiv1\;(mod\;p)\),则可以线性递推
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e6 + 20;
int inv[N];
int main()
{
int n, p;
scanf("%d%d", &n, &p);
inv[1] = 1; puts("1");
for(int i = 2; i <= n; ++ i)
{
inv[i] = (LL)(p - p / i) * inv[p % i] % p;
printf("%d\n", inv[i]);
}
return 0;
}
B - 除数函数求和 1
\(\sigma_k(n) = \sum_{d|n}d^k\), 求\(\sum_{i=1}^n\sigma_k(i)\)的值对\(10^9 + 7\)取模的结果.
考虑每个因子\(d\)对答案的贡献,即\(\sum\limits_{i = 1}^n i^k * \left\lfloor\dfrac{n}{i}\right\rfloor\)
然后暴力处理\(i^k\),复杂度\(O(nlogk)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int P = 1e9 + 7;
int pow_mod(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
b >>= 1;
}
return res;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
int res = 0;
for(int i = 1; i <= n; ++ i)
res = (res + (LL)n / i * pow_mod(i, k, P) % P) % P;
printf("%d", res);
return 0;
}
考虑继续优化:在求幂时有重复计算,因为每个数都可以唯一分解,所以只需要计算质因子的幂即可
考虑线性筛,用每个数的质因子的幂去计算它的幂.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int P = 1e9 + 7;
const int N = 1e7 + 10;
bool st[N];
int primes[N], cnt;
int mi[N];
int pow_mod(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
b >>= 1;
}
return res;
}
void init(int n, int k)
{
mi[1] = 1;
for(int i = 2; i <= n; ++ i)
{
if(!st[i])
{
primes[cnt ++ ] = i;
mi[i] = pow_mod(i, k, P);
}
for(int j = 0; primes[j] * i <= n; ++ j)
{
st[primes[j] * i] = 1;
mi[primes[j] * i] = (LL)mi[i] * mi[primes[j]] % P;
if(i % primes[j] == 0) break;
}
}
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
init(n, k);
int res = 0;
for(int i = 1; i <= n; ++ i)
res = (res + (LL)n / i * mi[i] % P) % P;
printf("%d\n", res);
return 0;
}
C - 除数函数求和 2
\(\sigma_k(i) = \sum_{d|i}d^k\)
求\(\sum_{i=1}^n2\sigma_2(i)+3\sigma_1(i)+5\sigma_0(i)\)对\(998244353\)取模.
和上题一样考虑每个因子的贡献,转化为求\(\sum\limits_{i=1}^n(2i^2+3i+5) * \left\lfloor\dfrac{n}{i}\right\rfloor\)
\(n\)的范围在\(10^9\)内,考虑整除分块
转化为\(2\sum\limits_{i=1}^ni^2\left\lfloor\dfrac{n}{i}\right\rfloor + 3\sum\limits_{i=1}^ni\left\lfloor\dfrac{n}{i}\right\rfloor + 5\sum\limits_{i=1}^n\left\lfloor\dfrac{n}{i}\right\rfloor\)
且已知:
\(\sum\limits_{i=1}^n1=n\)
\(\sum\limits_{i=1}^ni=\dfrac{(1+n)*n}{2}\)
\(\sum\limits_{i=1}^ni^2=\dfrac{n*(n+1)*(2n+1)}{6}\)
注:运算都是在\(mod\;p\)意义下的,故除法要乘逆元;且做减法后可能会出现负数,转化为\(mod\;p\)意义下的正数
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int P = 998244353;
const int inv3 = 332748118;
const int inv2 = 499122177;
int g(int k, int x)
{
return k / (k / x);
}
int f2(int l, int r)
{
int res1 = 1, res2 = 1;
l --;
res1 = (LL)res1 * l % P;
res1 = (LL)res1 * (l + 1) % P;
res1 = (LL)res1 * (2 * l + 1) % P;
res2 = (LL)res2 * r % P;
res2 = (LL)res2 * (r + 1) % P;
res2 = (LL)res2 * (2 * r + 1) % P;
int res = res2 - res1;
res = (res % P + P) % P;
res = (LL)res * inv3 % P;
return res;
}
int f1(int l, int r)
{
int res = 1;
res = (LL)res * (l + r) % P;
res = (LL)res * (r - l + 1) % P;
res = (LL)res * 3 % P;
res = (LL)res * inv2 % P;
return res;
}
int f0(int l, int r)
{
int res = 1;
res = (LL)res * (r - l + 1) % P;
res = (LL)res * 5 % P;
return res;
}
int main()
{
int n;
scanf("%d", &n);
int res = 0;
for(int l = 1, r; l <= n; l = r + 1)
{
r = min(n, g(n, l));
res = (res + (LL)f0(l, r) * (n / l) % P) % P;
res = (res + (LL)f1(l, r) * (n / l) % P) % P;
res = (res + (LL)f2(l, r) * (n / l) % P) % P;
}
printf("%d\n", res);
return 0;
}
D - 质数判定
判定输入的数是不是质数。
Miller_Rabin判质数,要用__int128或者快速乘
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
/*
LL mul(LL a, LL b, LL p)
{
__int128 x = a, y = b, m = p;
return (LL)(x * y % m);
}
*/
LL mul(ULL a, ULL b, LL p)
{
return (a * b - (ULL)((LD)a / p * b) * p + p) % p;
}
/*
LL mul(LL a, LL b, LL p)
{
LL res = 0;
while(b)
{
if(b & 1) res = (res + a) % p;
a = a * 2 % p;
b >>= 1;
}
return res;
}
*/
LL power(LL a, LL b, LL p)
{
LL res = 1;
while(b)
{
if(b & 1) res = mul(res, a, p);
a = mul(a, a, p);
b >>= 1;
}
return res;
}
LL p[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
bool Miller_Rabin(LL n)
{
if(n == 1) return 0;
for(int i = 1; i <= 9; ++ i)
{
if(p[i] == n) return 1;
else if(p[i] > n) return 0;
LL sum = power(p[i], n - 1, n), x = n - 1;
if(sum != 1) return 0;
while(sum == 1 && !(x % 2))
{
x >>= 1;
sum = power(p[i], x, n);
if(sum != 1 && sum != n - 1) return 0;
}
}
return 1;
}
int main()
{
LL n;
while(scanf("%lld", &n) == 1)
{
puts(Miller_Rabin(n) ? "Y" : "N");
}
return 0;
}
E - 乘法逆元 2
求\(\sum_{i=1}^na_i^{-1}\times998244353^{n-i}\;(mod\;p)\)
\(1 \le n \le 5000000,\;1\le a_i < p,\; p=10^9 + 7\)
解决此题之前先考虑如何\(O(n)\)求阶乘的逆元
考虑如下递推式:
令 \(infact[n]\) 为 \(n!\)的逆元
\(infact[i + 1] = \dfrac{1}{(i + 1)!}\)
\(infact[i + 1] * (i + 1) = \dfrac{1}{i!} = infact[i]\)
故我们可以求出\(n!\)的逆元,然后逆推,得到\(1...n!\)所有的逆元
同理,还可以用\(infact[i] * (i - 1)! = i^{-1}\),\(O(n)\)得到所有\(i\)的逆元
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e6 + 20;
int fact[N], infact[N];
int pow_mod(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
b >>= 1;
}
return res;
}
int main()
{
int n, p;
scanf("%d%d", &n, &p);
fact[0] = 1;
for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * i % p;
infact[n] = pow_mod(fact[n], p - 2, p);
for(int i = n - 1; i >= 1; -- i)
infact[i] = (LL)infact[i + 1] * (i + 1) % p;
for(int i = 1; i <= n; ++ i)
{
int res = (LL)infact[i] * fact[i - 1] % p;
printf("%d\n", res);
}
return 0;
}
本题可以考虑相同的思路
做前缀积 \(fact[n] = \prod\limits_{i=1}^na_i\)
求出\(infact[n]\),用\(infact[i + 1] * a_{i + 1} = infact[i]\)递推所有前缀积的逆元
然后用\(infact[i] * fact[i - 1] = a_i^{-1}\),\(O(n)\)得到所有\(a_i\)的逆元
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int P = 1e9 + 7;
const int M = 998244353;
const int N = 5e6 + 20;
int a[N];
int fact[N], infact[N];
int pow_mod(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
b >>= 1;
}
return res;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
fact[0] = 1;
for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * a[i] % P;
infact[n] = pow_mod(fact[n], P - 2, P);
for(int i = n - 1; i >= 1; -- i)
infact[i] = (LL)infact[i + 1] * a[i + 1] % P;
int ans = 0;
for(int i = 1; i <= n; ++ i)
{
int res = (LL)infact[i] * fact[i - 1] % P;
ans = (LL)ans * M % P;
ans = ((LL)ans + res) % P;
}
printf("%d\n", ans);
return 0;
}
F - 快速幂 2
求\(x^{a_i}\;(mod\;p)\)
\(1 \le n \le 5 \times 10^6,\;1\le x,a_i < p,\; p = 998244352\)
直接暴力快速幂的复杂度\(O(nlogp)\)
考虑分块预处理
\(y = \left\lfloor\dfrac{y}{k}\right\rfloor \cdot k + y \;mod\; k\)
\(x^y = x^{y\;mod\;k} \cdot x^{\left\lfloor\dfrac{y}{k}\right\rfloor \cdot k}\)
预处理复杂度\(O(k + \dfrac{p}{k})\), 当\(k\) 取 \(\sqrt p + 1\)时最优
预处理后即可\(O(1)\)回答每个询问
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e6 + 20;
const int P = 998244352;
int a[N], x_i[N], x_ki[N];
int x, n;
int main()
{
scanf("%d%d", &x, &n);
int k = sqrt(P) + 1;
x_i[0] = 1;
for(int i = 1; i <= k; ++ i) x_i[i] = (LL)x_i[i - 1] * x % P;
x_ki[0] = 1;
for(int i = 1; i <= P / k; ++ i) x_ki[i] = (LL)x_ki[i - 1] * x_i[k] % P;
for(int i = 1; i <= n; ++ i)
{
int y;
scanf("%d", &y);
int res = (LL)x_i[y % k] * x_ki[y / k] % P;
printf("%d ", res);
}
puts("");
return 0;
}
G - 二项卷积
H - 模立方根
I - ZQC 的作业
J - Humble Numbers
求第\(n\)个质因子只有\(2,3,5,7\)的数
#include <bits/stdc++.h>
using namespace std;
const int N = 6000;
int f[N];
void init()
{
f[1] = 1;
int a = 1, b = 1, c = 1, d = 1;
for(int i = 2; i <= 5842; ++ i)
{
f[i] = min(min(f[a] * 2, f[b] * 3), min(f[c] * 5, f[d] * 7));
if(f[i] == f[a] * 2) a ++;
if(f[i] == f[b] * 3) b ++;
if(f[i] == f[c] * 5) c ++;
if(f[i] == f[d] * 7) d ++;
}
}
int main()
{
init();
int n;
while(scanf("%d", &n) == 1 && n)
{
if(n % 10 == 1 && n % 100 != 11) printf("The %dst humble number is %d.\n", n, f[n]);
else if(n % 10 == 2 && n % 100 != 12) printf("The %dnd humble number is %d.\n", n, f[n]);
else if(n % 10 == 3 && n % 100 != 13) printf("The %drd humble number is %d.\n", n, f[n]);
else printf("The %dth humble number is %d.\n", n, f[n]);
}
return 0;
}
K - X问题
求在小于等于\(N\)的正整数中有多少个\(X\)满足:
\(X\;mod\;a_0=b_0,\;X\;mod\;a_1=b_1,\;X\;mod\;a_2=b_2,\;…,\;X\;mod\;a_i=b_i,\;…\;(0 < a_i \le 10)\)
扩展中国剩余定理, 去掉了模数两两互质的条件
先从两个方程入手
\(\begin{cases}x = k_1a_1 + m_1\\x = k_2a_2 + m_2\end{cases}\)
\(k_1a_1 + m_1 = k_2a_2 + m_2\)
\(k_1a_1 - k_2a_2 = m_2 - m_1\)
若\((a_1,a_2)\;|\;(m_2 - m_1)\),则有解
通解\(\begin{cases}k_1 + k\dfrac{a_2}{d}\\k_2 + k\dfrac{a_1}{d}\end{cases}\)
\(x = k_1a_1 + m_1 = (k_1 + k\dfrac{a_2}{d})a_1 + m_1\)
\(x = a_1k_1 + m_1 + k[a_1, a_2]\)
令\(a_1k_1 + m_1 = m\), \([a_1, a_2] = a\)
\(x = m + ka\)
则将两个不定方程合并成了一个,合并\(n - 1\)次后只剩一个方程
即为 \(x \equiv m\;(mod\;a)\)
最小正整数解即为\(m\;mod\;a\)的正余数,然后即可求出小于等于\(N\)的正整数中\(x\)的个数.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10 + 2;
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL a[N], b[N];
int main()
{
int __;
scanf("%d", &__);
while(__ -- )
{
LL n, m;
scanf("%lld%lld", &m, &n);
for(int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
for(int i = 1; i <= n; ++ i) scanf("%lld", &b[i]);
LL a1 = a[1], m1 = b[1];
bool flag = 0;
for(int i = 2; i <= n; ++ i)
{
LL a2 = a[i], m2 = b[i];
LL k1, k2;
LL d = exgcd(a1, a2, k1, k2);
if((m2 - m1) % d) { flag = 1; break; }
k1 *= (m2 - m1) / d;
LL t = a2 / d;
k1 = (k1 % t + t) % t;
m1 = a1 * k1 + m1;
a1 = abs(a1 / d * a2);
}
if(flag) puts("0");
else
{
LL res = (m1 % a1 + a1) % a1;
if(res > m) puts("0");
else if(res == 0) printf("%lld\n", (m - res) / a1);
else printf("%lld\n", (m - res) / a1 + 1);
}
}
return 0;
}
L - GCD
求满足\(a \le x \le b,\;c \le y \le d,\;gcd(x, y) = k\)的\((x,y)\)数量.
且(5,7)和(7,5)被认为是相同的.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 20;
int primes[N], cnt, mu[N], sum[N];
bool st[N];
void init()
{
mu[1] = 1;
for(int i = 2; i < N; ++ i)
{
if(!st[i])
{
primes[cnt ++ ] = i;
mu[i] = -1;
}
for(int j = 0; primes[j] * i < N; ++ j)
{
st[primes[j] * i] = 1;
if(i % primes[j] == 0) break;
mu[primes[j] * i] = -mu[i];
}
}
for(int i = 1; i < N; ++ i) sum[i] = sum[i - 1] + mu[i];
}
int g(int k, int x)
{
return k / (k / x);
}
LL f(int a, int b, int k)
{
LL res1 = 0, res2 = 0;
a = a / k, b = b / k;
int n = min(a, b);
for(int l = 1, r; l <= n; l = r + 1)
{
r = min(n, min(g(a, l), g(b, l)));
res1 += (LL)(sum[r] - sum[l - 1]) * (a / l) * (b / l);
}
for(int l = 1, r; l <= n; l = r + 1)
{
r = min(n, g(n, l));
res2 += (LL)(sum[r] - sum[l - 1]) * (n / l) * (n / l);
}
return res1 - res2 / 2;
}
int main()
{
init();
int __, cnt = 0;
scanf("%d", &__);
while(__ -- )
{
int a, b, c, d, k;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
if(k == 0) { printf("Case %d: 0\n", ++ cnt); continue; }
LL res = f(b, d, k) - f(a - 1, d, k) - f(b, c - 1, k) + f(a - 1, c - 1, k);
printf("Case %d: %lld\n", ++ cnt,res);
}
return 0;
}
M - GCD Again
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(scanf("%d", &n) == 1 && n)
{
int res = n, m = n;
for(int i = 2; i <= n / i; ++ i)
{
if(n % i == 0)
{
while(n % i == 0) n /= i;
res = res / i * (i - 1);
}
}
if(n > 1) res = res / n * (n - 1);
printf("%d\n",m - res - 1);
}
return 0;
}
N - The Euler function
求\(\sum\limits_{i=a}^bφ(i)\)
欧拉函数是积性函数,用线性筛预处理即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e6 + 20;
int primes[N], cnt;
int phi[N];
bool st[N];
void get_euler(int n)
{
phi[1] = 1;
for(int i = 2; i <= n; ++ i)
{
if(!st[i])
{
phi[i] = i - 1;
primes[cnt ++] = i;
}
for(int j = 0; primes[j] <= n / i; ++ j)
{
st[primes[j] * i] = 1;
if(i % primes[j] == 0)
{
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
}
}
int main()
{
get_euler(N - 1);
int a, b;
while(scanf("%d%d", &a, &b) == 2)
{
LL res = 0;
for(int i = a; i <= b; ++ i)
res += phi[i];
printf("%lld\n", res);
}
return 0;
}
O - Fansblog
P - Discrete Logging
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 2e5 + 3;
const int null = 0x3f3f3f3f;
typedef long long LL;
int Hash[N], h[N];
int find(int x)
{
int k = (x % N + N) % N;
while(Hash[k] != null && Hash[k] != x)
{
k ++;
if(k == N) k = 0;
}
return k;
}
bool count(int x)
{
int k = (x % N + N) % N;
while(1)
{
if(Hash[k] == null) return 0;
if(Hash[k] == x) return 1;
k ++;
if(k == N) k = 0;
}
return 0;
}
int bsgs(int a, int b, int p)
{
memset(Hash, 0x3f, sizeof Hash);
if(1 % p == b % p) return 0;
int k = sqrt(p) + 1;
for(int i = 0, j = b % p; i < k; ++ i)
{
int k = find(j);
Hash[k] = j;
h[k] = i;
j = (LL)j * a % p;
}
int ak = 1;
for(int i = 0; i < k; ++ i) ak = (LL)ak * a % p;
for(int i = 1, j = ak % p; i <= k; ++ i)
{
if(count(j)) return (LL)i * k - h[find(j)];
j = (LL)j * ak % p;
}
return -1;
}
int main()
{
int a, p, b;
while(scanf("%d%d%d", &p, &a, &b) == 3)
{
if(a == 0 && p == 0 && b == 0) break;
int res = bsgs(a, b, p);
if(res == -1) puts("no solution");
else printf("%d\n", res);
}
return 0;
}
Q - The Embarrassed Cryptographer
R - Minimum Sum LCM
S - GCD - Extreme (I)
T - Colossal Fibonacci Numbers!
U - One Friend at a Time
V - X^A Mod P
W - 乘法逆元
\(M\)和\(N\)互质,求满足K * M % N = 1的最小正整数K.
同A题,扩展欧几里得求逆元
#include <bits/stdc++.h>
using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
int n, m;
scanf("%d%d", &m, &n);
int x, y;
int d = exgcd(m, n, x, y);
printf("%d\n", (x % n + n) % n);
return 0;
}
X - 中国剩余定理
一个正整数\(K\),给出\(K\;Mod\;\)一些质数的结果,求符合条件的最小的\(K\)。
中国剩余定理
\(\begin{cases}x \equiv a_1\;(mod\;m_1)\\x \equiv a_2\;(mod\;m_2)\\...\\x \equiv a_k\;(mod\;m_k)\end{cases}\)
\(M = m_1m_2...m_k\)
\(M_i = \dfrac{M}{m_i}\)
\(M_i^{-1}\)表示\(M_i\)在\(mod\;m_i\)条件下的逆元
则\(x = a_1M_1M_1^{-1} + a_2M_2M_2^{-1} + ... + a_kM_kM_k^{-1}\)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10 + 2;
int n;
int A[N], B[N];
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()
{
scanf("%d", &n);
LL M = 1;
for(int i = 0; i < n; ++ i)
{
scanf("%d%d", &A[i], &B[i]);
M *= A[i];
}
LL res = 0;
for(int i = 0; i < n; ++ i)
{
LL Mi = M / A[i];
LL ti, y;
exgcd(Mi, A[i], ti, y);
res += B[i] * Mi * ti;
}
printf("%lld\n", (res % M + M) % M);
return 0;
}