望眉目有山河,清澈明朗;愿胸中有丘|

chfychin

园龄:1年7个月粉丝:3关注:3

数学知识--数论

目录

质数

素数定理:小于n的正整数大约有 nlnn 个素数

试除法判断素数O(n)

点击查看代码
bool is_prime(int x)
{
for(int i = 2; i <= x / i; i ++)
if(x % i == 0)
return false;
return true;
}

分解质因数 O(n)

点击查看代码
void getdiv(int x)
{
for(int i = 2; i <= x / i; i ++)
{
if(x % i == 0)
{
int s = 0;
while(x % i == 0) s ++, x /= i;
cout << i << ' ' << s << '\n';
}
}
if(x > 1) cout << x << ' ' << 1 << '\n';
}

素数筛

1. 诶氏筛法 O(nloglogn)

点击查看代码
void init_prime(int n)
{
for(int i = 2; i <= n; i ++)
if(!st[i])
{
prime[cnt ++] = i;
for(int j = i * i; j <= n; j += i)
st[j] = true;
}
}

线性筛 O(n)

点击查看代码
void init_prime(int n)
{
for(int i = 2; i <= n; i ++)
{
if(!st[i]) prime[cnt ++] = i;
for(int j = 0; prime[j] <= n / i; j ++)
{
st[i * prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
}

约数

唯一分解定理:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积:

N=p1a1p2a2···pkak

应用

1. 约数个数

若一个正整数S的标准分解式 N=p1a1p2a2···pkak,则其正因数个数:
S1(N)=(1+a1)(1+a2)···(1+ak)

点击查看代码
void S1(int x)
{
unordered_map<int,int> hash;
for(int i = 2; i <= x / i; i ++)
while(x % i == 0)
x /= i, hash[i] ++;
if(x > 1) hash[x] ++;
for(auto i:hash) ans = ans * (i.second + 1) % mod;
cout << ans << '\n';
}

2. 约数之和

N的正因数之和:S2(N)=(1+p1+p12+···+p1a1)(1+p2+p22+···+p2a2)···(1+pk+pk2+···+pkak)

点击查看代码
void S2(int x)
{
unordered_map<int, int> hash;
for(int i = 2; i <= x / i; i ++)
while(x % i == 0)
x /= i, hash[i] ++;
if(x > 1) hash[x] ++;
int ans = 1;
for(auto i : hash)
{
int a = i.first, b = i.second, t = 1;
while(b --) t = (a * t + 1) % mod;
ans = ans * t % mod;
}
cout << ans << '\n';
}

3. 求解 a,bgcd,lcm

gcd(a,b)=p1min(a1, b1)p2min(a2, b2)···pkmin(ak, bk)

lcm(a,b)=p1max(a1, b1)p2max(a2, b2)···pkmax(ak, bk)

4. 求组合数

在不取 mod 的情况下,用唯一分解求组合数:

C(n,m)=n!m!(nm)!

试除法求所有约数O(n)

点击查看代码
vector<int> get_x(int x)
{
vector<int> s;
for(int i = 2; i <= x / i; i ++)
if(x % i == 0)
{
s.push_back(i);
if(x / i != i)
s.push_back(x / i);
}
return s;
}

欧拉函数 O(logn)

欧拉函数:1N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ(N)。若在算数基本定理中,N=p1a1p2a2pmam,则:
ϕ(N)=N×p11p1×p21p2××pm1pm

点击查看代码
int erula(int x)
{
int ans = x;
for(int i = 2; i <= x / i; i ++)
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x % i == 0) x /= i;
}
if(x > 1) ans = ans / x * (x - 1);
return ans;
}

筛法求欧拉函数

(1) 质数i的欧拉函数即phi[i]=i−1,1 i−1均与i互质,共i−1个。

(2) phi[primes[j]∗i] 分为两种情况:

prime[j] | i : primes[j]i 的最小质因子,也是 primes[j]i 的最小质因子,因此 11/primes[j] 这一项在 phi[i] 中计算过了,只需将基数 N 修正为 primes[j] 倍,最终结果为phi[i]primes[j]
 : primes[j] 不是 i 的质因子,只是 primes[j]i 的最小质因子,因此不仅需要将基数N修正为 primes[j] 倍,还需要乘上 prime[j]1primes[j] 这一项,因此最终结果 phi[i](primes[j]1)

点击查看代码
void get_eulers(int n)
{
phi[1] = 1;
for(int i = 2; i <= n; i ++)
{
if(!st[i])
{
primes[cnt ++] = i;
phi[i] = i - 1;
}
for(int j = 0; primes[j] * i <= n; j ++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0)
{
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
}
}

例 可见的点

题目描述:

在一个平面直角坐标系的第一象限内,如果一个点 (x,y) 与原点 (0,0) 的连线中没有通过其他任何点,则称该点在原点处是可见的。

例如,点 (4,2) 就是不可见的,因为它与原点的连线会通过点 (2,1)

部分可见点与原点的连线如下图所示:

编写一个程序,计算给定整数 N 的情况下,满足 0xyN 的可见点 (xy) 的数量(可见点不包括原点)。

输入格式:

第一行包含整数 C,表示共有 C 组测试数据。

每组测试数据占一行,包含一个整数 N

输出格式:

每组测试数据的输出占据一行。

应包括:测试数据的编号(从 1 开始),该组测试数据对应的 N 以及可见点的数量。

同行数据之间用空格隔开。

输入

4
2
4
5
231

输出

1 2 5
2 4 13
3 5 21
4 231 32549

数据范围

1N,C1000

点击查看代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
using namespace std;
const int N = 1010;
int prime[N], phi[N];
bool st[N];
int n, cnt, t, ans;
void init()
{
st[1] = 1;
for(int i = 2; i < N; i ++)
{
if(!st[i])
{
prime[cnt ++] = i;
phi[i] = i - 1;
}
for(int j = 0; prime[j] * i <= N; j ++)
{
st[i * prime[j]] = true;
if(i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * (prime[j]);
break;
}
else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
void solve()
{
cin >> n;
t ++, ans = 0;
for(int i = 1; i <= n; i ++)
ans += phi[i] * 2;
cout << t << ' ' << n << ' ' << ans + 3 << '\n';
}
int main()
{
IOS;
init(); int T = 1;
cin >> T;
while(T --)
solve();
return T ^ T;
}

快速幂 O(logn)

数的乘方满足性质:anam=a(n+m)

又因
n=20+21+22+···+2k1
m=20+21+22+···+2k2

故可预处理出a20,a21,a22,···,a2log n+m

b=n+m

aba20,a21,a22,···a2log b,即组合成ab=a2x1×a2x1×a2x2×···×a2xt

二进制可以表示所有数,且用单一用二进制表示时,b单一表示最大可表示为二进制形式的2logb

点击查看代码
int qmi(int a, int b, int p)
{
int ans = 1;
while(b)
{
if(b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}

快速幂求逆元 O(logn)

**乘法逆元的定义:若整数 bm 互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得 a/ba×x(modm),则称 xb 的模 m 乘法逆元,记为 b1(modm)
b 存在乘法逆元的充要条件是 b 与模数 m 互质当模数 m 为质数时,bm2 即为 b 的乘法逆元。

裴属定理(贝祖定理):对于任意不全为零的整数 a,b ,存在 x,y , 使得 ax+by=gcd(a,b)

费马小定理:假如 a 是一个整数,p 是一个质数,则 p|(apa),即 apa(mod p),如果 a 不是 p 的倍数,则有 ap11(mod p)

bm互质,有

a/ba×x(mod m)

bx1(mod m)

又有bm11(mod m)

x=b1=bm2

bm 的乘法逆元即为 bm2

点击查看代码
int qminv(int a, int p)
{
int ans = 1, b = p - 2;
while(b)
{
if(b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}

矩阵乘法 O(n3log(m))

矩阵的乘积和数的乘积具有类似的幂次性:FnaFnb=Fna+b

[a11a12a13a21a22a23a31a32a33]m×[a11a12a13a21a22a23a31a32a33]n=[a11a12a13a21a22a23a31a32a33](n+m)

可利用矩阵的幂次性结合快速幂加速求解一些有关系的数据

令矩阵a为系数矩阵, F 为关系矩阵,则有 fnA=Fn+1

[fnfn+1fn+2]×[a11a12a13a21a22a23a31a32a33]=[fn+1fn+2fn+3]

一般关系矩阵由问题给出,系数矩阵要根据关系矩阵的关系推导出来

例1. Fibonacci数列第n项

题目描述:

大家都知道,斐波那契数列是满足如下性质的一个数列:

Fn={1,x2Fn1+Fn2,x3

请你求出 Fnmod 109+7 的值。

输入格式:

一行一个正整数 n

输出格式:

输出一行一个整数表示答案。

输入1

5

输出1

5

输入2

10

输出2

55

数据范围

对于 60% 的数据,1n92
对于 100% 的数据,1n<263

点击查看代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
#define mod1 1000000007
#define mod2 998244353
using namespace std;
typedef __int128 i128;
const int N = 2;
void mul(int c[][N], int b[][N], int a[][N])
{
int t[N][N];
memset(t, 0, sizeof t);
for(int i = 0; i < N; i ++)
for(int j = 0; j < N; j ++)
for(int k = 0; k < N; k ++)
t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % mod1;
memcpy(c, t, sizeof t);
}
void solve()
{
int n;
cin >> n; n --;
int f[N][N] = {1, 1};
int a[N][N] = {
{0, 1},
{1, 1}
};
while(n)
{
if(n & 1) mul(f, a, f);
mul(a, a, a);
n >>= 1;
}
cout << f[0][0] << '\n';
}
signed main()
{
IOS; int _ = 1;
while(_ --)
solve();
return _ ^ _;
}

例2. Fibonacci前n项和

题目描述:

佳佳对数学,尤其对数列十分感兴趣。

在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。

例如用 S(n) 表示 Fibonaccin 项和 modm 的值,即 S(n)=(F1+F2++Fn)mod m,其中 F1=F2=1,Fi=Fi1+Fi2

可这对佳佳来说还是小菜一碟。

终于,她找到了一个自己解决不了的问题。

T(n)=(F1+2F2+3F3++nFn)mod m 表示Fibonacci 数列前 n 项变形后的和 mod m 的值。

现在佳佳告诉你了一个 nm,请求出 T(n) 的值。

输入格式:

共一行,包含两个整数 nm

输出格式:

共一行,输出 T(n) 的值。

输入

5 5

输出

1

数据范围与解释

1n,m2311
T(5)=(1+2×1+3×2+4×3+5×5)mod 5=1

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
using namespace std;
const int N = 4, M = 50;
int n, m;
void mul(int c[][N], int a[][N], int b[][N])
{
static int t[N][N];
memset(t, 0, sizeof t);
for(int i = 0; i < N; i ++)
for(int j = 0; j < N; j ++)
for(int k = 0; k < N; k ++)
t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % m;
memcpy(c, t, sizeof t);
}
void solve()
{
cin >> n >> m;
int f1[N][N] = {1, 1, 1, 0};
int a[N][N] = {
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 1, 1},
{0, 0, 0, 1},
};
int k = n - 1;
while(k)
{
if(k & 1) mul(f1, f1, a);
mul(a, a, a);
k >>= 1;
}
cout << ((n * f1[0][2] - f1[0][3]) % m + m) % m << '\n';
}
signed main() {
IOS; int _ = 1;
// cin >> _;
while(_ --)
solve();
return _ ^ _;
}

扩展欧几里得

1.扩展欧几里得

用于求解ax+by=gcd(a,b)的解,利用辗转相除法构造出x,y的通解

b=0时,ax+by=a,可令x=1y=0

b0时,因

gcd(a,b) = gcd(b,a % b)

bx + (a % b)y = gcd(b,a % b)
bx + (aa/bb)y = gcd(b,a % b)
ay + b(xa/by) = gcd(b,a % b)=gcd(a,b)

x=y,y=xa/by

因此可以递归求解gcd(a,b),求出下一层的xy,再回溯过程用上式即可

2.一般的同余方程 ax + by = c

可设d=gcd(a,b),则其有解当且仅当d|c

求解:

用扩展欧几里得求出ax0+by0=d

a(x0c/d)+b(y0c/d)=c

故而特解为x=x0c/d,y=y0c/d

通解 = 特解 + 齐次解

而齐次解即为方程ax+by=0

故而通解为

x=x+kb/dy=yka/dkz

若令t=b/d,则对于x的最小非负整数解为(x%t + t)%t

3.应用:求解一次同余方程 ax ≡ b(mod m)

等价于求解

ax=m(y)+b
ax+my=b

有解条件为gcd(a,m)|b,然后用扩展欧几里得求解即可

b=1am互质,所求的x即为a的逆元

例1. 扩展欧几里得

题目描述:

给定 n 对正整数 ai,bi,对于每对数,求出一组xi,yi,使其满足 ai×xi+bi×yi=gcd(ai,bi)

输入格式:

第一行包含整数 n
接下来 n 行,每行包含两个整数 ai,bi

输出格式:

输出共 n 行,对于每组 ai,bi,求出一组满足条件的 xi,yi,每组结果占一行。
本题答案不唯一,输出任意满足条件的 xi,yi 均可。

输入

2
4 6
8 18

输出

-1 1
-2 1

数据范围

1n105,1ai,bi2×109

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
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;
}
void solve()
{
int a, b, x, y;
cin >> a >> b;
int d = exgcd(a, b, x, y);
cout << x << ' ' << y << '\n';
}
signed main()
{
IOS;
int _ = 1;
cin >> _;
while(_ --)
solve();
return 0;
}

例2. 求解同余方程

题目描述:

给定 n 组数据 ai,bi,mi,对于每组数求出一个xi,使其满足 ai×xibi(modmi),如果无解则输出 impossible

输入格式:

第一行包含整数 n
接下来 n 行,每行包含一组数据 ai,bi,mi

输出格式:

输出共 n 行,每组数据输出一个整数表示一个满足条件的 xi,如果无解则输出impossible
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 int 范围之内。

输入

2
2 3 6
4 3 5

输出

impossible
-3

数据范围

1n105,1ai,bi,mi2×109

点击查看代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
using namespace std;
using LL = long long;
int n, x, y;
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
int z = x;
x = y, y = z - a / b * y;
return d;
}
void solve()
{
int a, b, m;
cin >> a >> b >> m;
int d = exgcd(a, m, x, y);
if(b % d) cout << "impossible\n";
else
{
x = (LL) x * b / d % m;
cout << x << endl;
}
}
signed main()
{
IOS;
int _;
cin >> _;
while(_ --)
solve();
return _ ^ _;
}

例3. 青蛙的约会

题目描述:

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。

我们把这两只青蛙分别叫做青蛙 A 和青蛙 B,并且规定纬度线上东经 0 度处为原点,由东往西为正方向,单位长度 1 米,这样我们就得到了一条首尾相接的数轴。设青蛙 A 的出发点坐标是 x,青蛙 B 的出发点坐标是 y。青蛙 A 一次能跳 m 米,青蛙 B 一次能跳 n 米,两只青蛙跳一次所花费的时间相同。纬度线总长 L 米。现在要你求出它们跳了几次以后才会碰面。

输入格式:

输入只包括一行五个整数 x,y,m,n,L

输出格式:

输出碰面所需要的次数,如果永远不可能碰面则输出一行一个字符串 Impossible

输入

1 2 3 4 5

输出

4

数据范围

对于 100% 的数据,1xy2×1091m,n2×1091L2.1×109

点击查看代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
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;
}
void solve()
{
int a, b, m, n, l;
cin >> a >> b >> m >> n >> l;
int x, y;
int d = exgcd(n - m, l, x, y);
if((a - b) % d) cout << "Impossible\n";
else
{
int s = (a - b) / d * x;
int t = abs(l / d);
cout << (s % t + t) % t << '\n';
}
}
signed main()
{
IOS; int _ = 1;
// cin >> n;
while(_ --)
solve();
return _ ^ _;
}

中国哦剩余定理(孙子定理)

{xa1(mod m1)xa2(mod m2)..·xan(mod mn)

{M=m1m2m3...mnMi=MmitiMimiMiti1(mod mi)

i=1naiMiti

1. 将式子等价转换

对于每两个式子(考虑将其合并):

xm1(mod a1)

xm2(mod a2)

则有:

x=k1a1+m1

x=k2a2+m2

进而:

k1a1+m1=k2a2+m2

k1a1k2a2=m2m1

即:

k1a1+k2(a2)=m2m1

也就是需要找到一个最小的 k1,k2,使得等式成立(因为要求x最小,而 am 都是正数)。

2. 用扩展欧几里得算法找出一组解

已知 a1,m1,a2,m2,可以用扩展欧几里得算法算出一个 k1,k2 使得:

k1a1+k2(a2)=gcd(a1,a2)

无解判断:

gcd(a1,a2)(m2m1),则无解。

d=gcd(a1,a2),y=(m2m1)d

依上文,只需让k1,k2分别扩大y倍,则可以找到一个k1,k2满足①式:

k1=k1y,k2=k2y

3. 找到最小正整数解

已知性质:

k1=k1+ka2d
k2=k2+ka1d

k 为任意整数,这时新的 k1,k2 仍满足①式。

证明:

将新的 k1,k2 带入式子得:

(k1+ka2d)a1+(k2+ka1d)(a2)=m2m1

裂项,拆负号化简:

k1a1+ka2a1d+k2(a2)+ka1(a2)d=m2m1

k1a1+k2(a2)+ka2a1dka1a2d=m2m1

k1a1+k2(a2)=m2m1

这个式子和①是一样的,因 成立,故此式也成立。

要找一个最小的非负整数解,只需让

k1=k1%abs(a2d)
k2=k2%abs(a1d)

即可找到当前最小的 k1,k2 的解,即此时的 k0

因为不知道 a2d 的正负性,在原基础上要尽量减多个 abs(a2d),使其为正整数且最小。

4. 等效替代:

式带入

新的x为:

x=(k1+ka2d)a1+m1

=k1a1+m1+ka2a1d

=k1a1+m1+klcm(a1,a2)

这只是前两个式子得最小k,有可能遇到下一个式子后面被迫要扩大

中,设a0=lcm(a1,a2),m0=k1a1+m1

则:

=ka0+m0

这个形式与一开始分解的形式特别像

假设之后又来了一个 a3,m3,只需要继续找:

x=ka0+m0=k3(a3)+m3 ,那么问题又回到了第一步。

5. 总结

此做法相当于每次考虑合并两个式子,将这n个式子合并 n1 次后变为一个式子。最后剩下的式子就满足我们的答案。

注意:

(1)lcm(a1,a2)%a2d,需要取绝对值。又因为 d=gcd(a1,a2),我们不知道a1的正负性(可能是上一步推过来的)。

(2)%a2d,需要取绝对值, 膜负数的话,不会取到正解;

例1. 表达整数的奇怪方式

题目描述:

给定 2n 个整数 a1,a2,,anm1,m2,,mn,求一个最小的非负整数 x,满足 i[1,n],xmi(modai)

输入格式:

1 行包含整数 n

2n+1 行:每 i+1 行包含两个整数 aimi,数之间用空格隔开。

输出格式:

输出最小非负整数 x,如果 x 不存在,则输出 1
如果存在 x,则数据保证 x 一定在 64 位整数范围内。

输入

2
8 7
11 9

输出

31

数据范围

1ai2311,0mi<ai,1n25

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
using namespace std;
int n;
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 inline mod(int a, int b)
{
return ((a % b) + b) % b;
}
void solve()
{
cin >> n;
int a1, m1;
cin >> a1 >> m1;
for(int i = 1; i < n; i ++)
{
int a2, m2, k1, k2;
cin >> a2 >> m2;
int d = exgcd(a1, -a2, k1, k2);
if((m2 - m1) % d)
{
puts("-1");
return ;
}
k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d));
m1 = k1 * a1 + m1;
a1= abs(a1 / d * a2);
}
cout << m1 << endl;
}
signed main()
{
IOS;
int _ = 1;
// cin >> _;
while(_ --)
solve();
return _ ^ _;
}

例2. 曹冲养猪

题目描述:
自从曹冲搞定了大象以后,曹操就开始琢磨让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲很不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。

举个例子,假如有 16 头母猪,如果建了 3 个猪圈,剩下 1 头猪就没有地方安家了;如果建造了 5 个猪圈,但是仍然有 1 头猪没有地方去;如果建造了 7 个猪圈,还有 2 头没有地方去。

你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

输入格式:

第一行包含一个整数 n,表示建立猪圈的次数;

接下来 n 行,每行两个整数 ai,bi,表示建立了 ai 个猪圈,有 bi 头猪没有去处。

你可以假定 ai,aj 互质。

输出格式:

输出仅包含一个正整数,即为曹冲至少养猪的数目。

输入

3
3 1
5 1
7 2

输出

16

数据范围

1n10,1biai1100000
所有ai的乘积不超过 1018

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr)
#define int long long
using namespace std;
const int N = 15;
int m[N], a[N];
int n;
void exgcd(int a, int b, int &x, int &y)
{
if(!b) x = 1, y = 0;
else
{
exgcd(b, a % b, y, x);
y -= a / b * x;
}
}
void solve()
{
cin >> n;
int M = 1;
for(int i = 0; i < n; i ++)
{
cin >> m[i] >> a[i];
M *= m[i];
}
int ans = 0;
for(int i = 0; i < n; i ++)
{
int mi = M / m[i];
int ti, y;
exgcd(mi, m[i], ti, y);
ans += mi * a[i] * ti;
}
cout << (ans % M + M) % M << endl;
}
signed main()
{
IOS;
int _ = 1;
// cin >> _;
while(_ --)
solve();
return _ ^ _;
}

本文作者:chfychin

本文链接:https://www.cnblogs.com/chfychin/p/17741732.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   chfychin  阅读(48)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起