算法之数论应用篇二
最大公约数
线性筛
void get_primes(int n ){
for(int i = 2 ; i <= n ; ++i)
{
if(!st[i])primes[cnt ++] = i;
for(int j = 0 ; primes[j] <= n / i; ++j){
st[i*primes[j]] = true;
if(i % primes[j] == 0)break;
}
}
}
利用了每个合数必有一个最小素因子。每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
代码中体现在:
if(i%prime[j]==0)break;
prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。
因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。
在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,pr[j]必定是pr[j]*i的最小因子.
Hankson的趣味题
解题思路
这题是求满足条件的x分个数。条件是 gcd(a,x) = b , lcm(x,c) = d;
由lcm(c,x) = d ,我们知道x 一定为d的约数。那么我们就可以从d的约数中找符合条件的x。不过因为在找约数的时间复杂度是
d
\sqrt{d}
d的,我们需要进行一些优化。我们知道一个数的余数可以有其分解质因数的质因子组合而成。因此我们就可以将d先进行分解质因数,之后通过dfs进行组合形成约数。因为2∗109内的数含有的不同质因子的个数不会超过10个(上一篇提到),因此速度会得到很大的优化。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 2000 , M = 50010 ;
typedef long long LL;
int n ;
int primes[M] , cnt;
bool st[M];
struct Factor{
int p , s ;
}factor[M];
int fcnt ,dcnt;
int divtor[M];
void get_primes(int n ){
for(int i = 2 ; i <= n ; ++i)
{
if(!st[i])primes[cnt ++] = i;
for(int j = 0 ; primes[j] <= n / i; ++j){
st[i*primes[j]] = true;
if(i % primes[j] == 0)break;
}
}
}
int gcd(int a , int b){
if(b == 0 )return a;
else return gcd(b , a % b);
}
void divite(int n ){
fcnt = 0;
for(int i = 0 ; i < cnt && primes[i] <= n / primes[i] ; ++i){
int p = primes[i];
if(n % p == 0){
int s = 0;
while(n % p == 0) n /= p , s ++;
factor[++fcnt] = {p,s};
}
}
if(n > 1)factor[++fcnt] = { n ,1};
}
void dfs(int u , int p){
if( u > fcnt){
divtor[dcnt++] = p;
return ;
}
for(int i = 0 ; i <= factor[u].s ; ++i){
dfs(u+1 , p);
p *= factor[u].p;
}
}
int main(){
get_primes(M - 1);
cin>>n;
while(n--){
int a ,b , c ,d;
cin>>a>>b>>c>>d;
divite(d);
dcnt = 0;
dfs(1,1);
int res = 0;
for(int i = 0 ; i < dcnt ; ++i){
int x = divtor[i];
if(gcd(a,x) == b && (LL)c * x / gcd(x,c) == d) res++;
}
cout<<res<<endl;
}
return 0;
}
欧拉函数
前言
欧拉函数是一个函数嘛?不它不是的!对于一个数N的欧拉函数我们常记作 ψ ( N ) \psi(N) ψ(N),它的含义是从1~N中与N互质的个数。
其中
ψ
(
N
)
=
N
∗
Π
质
数
p
∣
N
p
−
1
p
\psi(N) = N * \Pi_{质数p|N}\frac{p-1}{p}
ψ(N)=N∗Π质数p∣Npp−1
可见的点(数学知识+欧拉函数)
解题思路
分析题目容易发现,除了(1,0),(0,1)和(1,1)这三个钉子外,一个钉子(x,y)能被看到,当且仅当1≤x,y≤N.x+y并且ged(x,y)=1。
在
1
≤
x
,
y
≤
N
,
x
≠
y
1≤x,y≤N,x \ne y
1≤x,y≤N,x=y中能看到的钉子关于过(0,0)和(N,N)的直线对称。我们可以考虑其中的一半,即1≤x<y≤N。换言之,对于每个2≤y≤N,我们需要统计有多少个x满足1≤x<y并且gcd(x,y)=1。这样的x的数量恰好就是(y)。
综上所述,本题的答案就是
3
+
2
∗
Σ
i
=
2
N
ψ
(
i
)
。
3+2* \Sigma_{i=2}^N\psi(i)。
3+2∗Σi=2Nψ(i)。我们要做的事情就是求出2~N中每个数的欧拉函数.
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n ;
int primes[N];
int phi[N];
void init(int n){
for(int i = 1 ; i <= n ; ++i)phi[i] = i;
for(int i = 2 ; i <= n; ++i){
if(phi[i] == i)
for(int j = 1 ; j <= n / i ; ++j)
phi[j*i] = phi[j*i]/i * (i-1);
}
}
int main(){
init(N-1);
int T ;
cin>>T;
for(int i = 1; i <= T ; ++i){
cin>>n;
int res = 0;
for(int i = 2 ; i <= n ; ++i) res += phi[i];
cout<<i<<" "<<n<<" "<< res * 2 + 3 <<endl;
}
return 0;
}
最大公约数(可见的点扩展)
解题思路
之所以说是上一题的扩展是有原因的,对于这个题目是求 1 - N ,中 满足
g
c
d
(
x
,
y
)
=
p
,
p
是
质
数
gcd(x,y) = p ,p是质数
gcd(x,y)=p,p是质数的点对数。两个数x,y之间的最大公约数为p,那么其除以p之后也就是
g
c
d
(
x
/
p
,
y
/
p
)
=
1
gcd(x/p,y/p) = 1
gcd(x/p,y/p)=1因为p是它们的最大公约数。而知就转换成了上一题。有一些出入的就是这里是从 1 开始计数的,同时对于每一个p我们加上 1 ~ N/p 范围内对于上一题的解。
解题步骤
- 线性筛,得到2-N的所有质数,同时得到2-N的欧拉函数。
- 之后将2-N的欧拉函数建立前缀和。
- 枚举每一个质数,加上 sum(n/p) * 2 + 1
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 1E7 + 10;
int n ;
int primes[N] ,phi[N];
int st[N] , cnt;
LL sum[N];
void init(int n ){
for(int i = 2 ; i <= n ; ++i){
if(st[i] == 0){
primes[cnt++] = i;
phi[i] = i-1;
}
for(int j = 0; primes[j] <= n / i ; ++j){
st[primes[j] * i] = 1;
if( i % primes[j] == 0){
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * ( primes[j] - 1) ;
}
}
for(int i = 1 ; i <= n ; ++i)sum[i] = sum[i-1] + phi[i];
}
int main(){
cin>>n;
init(n);
LL ans = 0;
for(int i = 0 ; i < cnt ; ++i)
ans += sum[n/primes[i]]*2 + 1 ;
cout<<ans <<endl;
return 0;
}
同余
取模的性质
在介绍有关同余的一系列性质之前有必要列举一下取模的一些性质
定义
给定一个正整数p,任意一个整数n,一定存在等式 :
n = kp + r ;
其中 k、r 是整数,且 0 ≤ r < p,则称 k 为 n 除以 p 的商,r 为 n 除以 p 的余数。
对于正整数 p 和整数 a,b,定义如下运算:取模运算:a % p(或a mod p),表示a除以p的余数。
说明:
- 同余式:正整数a,b对p取模,它们的余数相同,记做 或者a ≡ b (mod p)。
- n % p 得到结果的正负由被除数n决定,与p无关。例如:7%4 = 3, -7%4 = -3, 7%-4 = 3, -7%-4 = -3
基本性质
- 若p|(a-b),则a≡b (% p)。例如 11 ≡ 4 (% 7), 18 ≡ 4(% 7)
- 取模运算是等价关系。
自反性:(a % p)=(a % p)意味a≡a (% p)
对称性:a≡b (% p)等价于b≡a (% p)
传递性:若a≡b (% p)且b≡c (% p) ,则a≡c (% p)
运算规则
模运算与基本四则运算有些相似,但是除法例外。其规则如下:
- (a + b) % p = (a % p + b % p) % p
- (a - b) % p = (a % p - b % p) % p
- (a * b) % p = (a % p * b % p) % p
- a ^ b % p = ((a % p)^b) % p
因此对于除法取模,我们就会利用乘法逆元来解决。下面我们会提到如何求乘法逆元。
重要定理
- 若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);因为由 a = k1p + x , b = k2p + x , 那么同时加上一个数c后,对p的余数都是 (x + c) % p 是一样的
- 若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);与上面同理
- 若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),
(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p); 我们证明加法,其余同理。由前提我们令
a = k 1 ∗ p + x , b = k 2 ∗ p + x , c = k 3 ∗ p + y , d = k 4 ∗ p + y a = k_1*p + x , b = k_2*p+x , c = k_3*p+y , d = k_4*p+y a=k1∗p+x,b=k2∗p+x,c=k3∗p+y,d=k4∗p+y那么 ( a + c ) = ( k 1 + k 3 ) ∗ p + x + y ( b + d ) = ( k 2 + k 4 ) ∗ p + x + y (a+c) = (k_1+k_3)*p+x+y \quad (b+d) =(k_2+k_4)*p+x+y (a+c)=(k1+k3)∗p+x+y(b+d)=(k2+k4)∗p+x+y它们对p取模的结果都是 ( x + y ) (x+y)%p (x+y)
重要定理
费马小定理
费马小定理:
a
(
p
−
1
)
≡
1
(
m
o
d
p
)
a^(p-1) ≡ 1(mod p)
a(p−1)≡1(modp)
前提:p为质数,且a,p互质
在证明之前我们先证明两个引理
- 如 果 p , c 互 质 , 并 且 a ∗ c ≡ b ∗ c ( m o d p ) , 则 a ≡ b ( m o d p ) 如果p,c互质,并且a*c≡b*c(mod p) , 则 a ≡b (mod p) 如果p,c互质,并且a∗c≡b∗c(modp),则a≡b(modp) :对于同余我们就可以写成。 a·c≡b·c(mod m)可得ac–bc≡0(mod m)可得(a-b)·c≡0(mod m)。因为(m,c)=1即m,c互质,c可以约去,a– b≡0(mod m)可得a≡b(mod m)。
- 设 m 是 一 个 整 数 且 m > 1 , b 是 一 个 整 数 且 ( m , b ) = 1 。 如 果 a [ 1 ] , a [ 2 ] , a [ 3 ] , a [ 4 ] , … a [ m ] 是 模 m 的 一 个 完 全 剩 余 系 , 则 b ⋅ a [ 1 ] , b ⋅ a [ 2 ] , b ⋅ a [ 3 ] , b ⋅ a [ 4 ] , … b ⋅ a [ m ] 也 构 成 模 m 的 一 个 完 全 剩 余 系 。 设m是一个整数且m>1,b是一个整数且(m,b)=1。如果a[1],a[2],a[3],a[4],…a[m]是模m的一个完全剩余系,则b·a[1],b·a[2],b·a[3],b·a[4],…b·a[m]也构成模m的一个完全剩余系。 设m是一个整数且m>1,b是一个整数且(m,b)=1。如果a[1],a[2],a[3],a[4],…a[m]是模m的一个完全剩余系,则b⋅a[1],b⋅a[2],b⋅a[3],b⋅a[4],…b⋅a[m]也构成模m的一个完全剩余系。 证明: 假设不是完全剩余系,那么至少有两个同余,即 b ∗ a [ i ] ≡ b ∗ a [ j ] ( m o d m ) b*a[i]≡b*a[j](mod m) b∗a[i]≡b∗a[j](modm)有定理一有 a [ i ] ≡ a [ j ] ( m o d m ) a[i]≡a[j](mod m) a[i]≡a[j](modm),因为这两个是完全剩余系中不同的,因此不可能成了。证毕
- 费马小定理证明:0,1,2,3,4…p-1是p的完全剩余系
∵a,p互质
∴a,2a,3a,4a…(p-1)a也是mod p的完全剩余系
∴123…(p-1)a ≡ a2a3a…(p-1)*a (mod p)
∴ (p-1)! ≡ (p-1)!*a^(p-1) (mod p)
两边同时约去(p-1)!
a^(p-1) ≡ 1 (mod p) - 推广: 若 p 是 质 数 , 则 对 于 任 意 的 整 数 a , 有 a p ≡ a ( m o d p ) 若p是质数,则对于任意的整数a,有a^p≡ a(mod p) 若p是质数,则对于任意的整数a,有ap≡a(modp) ,证明: p ∣ a ( a p − 1 − 1 ) , 若 a , p 互 质 , 那 么 由 定 理 知 成 立 , 如 果 不 互 质 , 那 么 p 与 a 同 时 除 以 g c d ( p , a ) 的 结 果 会 p / g c d ) 会 与 a 互 质 , 则 成 立 p|a(a^{p-1}-1),若a,p互质,那么由定理知成立,如果不互质,那么p与a同时除以gcd(p,a)的结果会p/gcd)会与a互质,则成立 p∣a(ap−1−1),若a,p互质,那么由定理知成立,如果不互质,那么p与a同时除以gcd(p,a)的结果会p/gcd)会与a互质,则成立
欧拉定理
对于费马定理,我们知道 p(质数)的欧拉函数就是 p - 1
因此可以成
若
正
整
数
a
,
n
互
质
,
则
a
ψ
(
n
)
≡
1
(
m
o
d
)
n
若正整数a,n互质,则a^{\psi(n)}≡1 (mod)n
若正整数a,n互质,则aψ(n)≡1(mod)n
推论
若
正
整
数
a
,
n
互
质
,
则
对
于
任
意
正
整
数
b
,
有
a
b
≡
a
b
m
o
d
ψ
(
n
)
(
m
o
d
)
n
若正整数a,n互质,则对于任意正整数b,有a^{b}≡a^{b mod \psi(n)}(mod)n
若正整数a,n互质,则对于任意正整数b,有ab≡abmodψ(n)(mod)n
而这个就是快速幂取模可行的一个依据
扩展欧几里得算法
定理
对
于
任
意
整
数
a
,
b
,
存
在
一
对
整
数
x
和
y
,
满
足
a
x
+
b
y
=
g
c
d
(
a
,
b
)
对于任意整数a,b,存在一对整数x和y,满足ax + by = gcd(a,b)
对于任意整数a,b,存在一对整数x和y,满足ax+by=gcd(a,b)
证明
在欧几里得算法的最后一步,即b=0时,显然有一对整数x=1,y=0,使得
a
∗
1
+
0
∗
0
=
g
c
d
(
a
,
0
)
。
a*1+0*0=gcd(a,0)。
a∗1+0∗0=gcd(a,0)。
若b>0,则
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
m
o
d
b
)
。
gcd(a,b)=gcd(b,a mod b)。
gcd(a,b)=gcd(b,amodb)。假设存在一对整数x,y,满足
b
∗
x
+
(
a
m
o
d
b
)
∗
y
=
g
c
d
(
b
,
a
m
o
d
b
)
b*x+(amodb)*y=gcd(b,a mod b)
b∗x+(amodb)∗y=gcd(b,amodb),因为
b
x
+
(
a
m
o
d
b
)
y
=
b
x
+
(
a
−
⌊
a
/
b
⌋
b
]
)
∗
y
=
a
y
+
b
(
x
−
[
a
/
b
]
y
)
bx+(amodb)y=bx+(a-\lfloor a/b\rfloor b])*y=ay+b(x-[a/b]y)
bx+(amodb)y=bx+(a−⌊a/b⌋b])∗y=ay+b(x−[a/b]y),所以令
x
′
=
y
,
y
′
=
x
−
∣
a
/
b
∣
y
,
x′=y,y′=x−∣a/b∣y,
x′=y,y′=x−∣a/b∣y, 就得到了 。ax′+by′=gcd(a,b)。 对欧几里得算法的递归过程应用数学归纳法,可知Bézout定理成立。
证毕。
代码:
int exgcd(int a , int b ,int & x ,int & y){
if(b == 0){
x = 1 , y = 0;
return a;
}
int d = exgcd(b , a % b , y ,x);
y -= a / b * x;
对于更为一般的方程ax+by=c,它有解当且仅当d|c。(d = gcd(a,b))我们可以先求出
a
x
+
b
y
=
d
的
一
组
特
解
x
o
,
y
o
,
然
后
令
x
o
,
y
o
同
时
乘
上
c
/
d
,
就
得
到
了
a
x
+
b
y
=
c
的
一
组
特
解
(
c
/
d
)
∗
x
o
,
(
c
/
d
)
∗
y
o
。
ax+by=d的一组特解x_o,y_o,然后令x_o,y_o同时乘上c/d,就得到了ax+by=c的一组特解(c/d)* x_o,(c/d)* y_o。
ax+by=d的一组特解xo,yo,然后令xo,yo同时乘上c/d,就得到了ax+by=c的一组特解(c/d)∗xo,(c/d)∗yo。
事实上,方程ax+by=c的通解可以表示为:
x
=
c
d
∗
x
0
+
(
k
b
d
)
y
=
c
d
∗
y
0
−
(
k
∗
a
d
)
(
k
∈
Z
)
x=\frac {c}{d}*x_0+(k\frac {b}{d}) \quad y=\frac {c}{d}*y_0 -(k*\frac {a}{d}) (k∈Z)
x=dc∗x0+(kdb)y=dc∗y0−(k∗da)(k∈Z)
其中k取遍整数集合.
乘法逆元
定理
若
b
,
p
互
质
,
并
且
b
∣
a
,
则
存
在
一
个
整
数
x
,
使
得
a
b
≡
a
∗
x
(
m
o
d
p
)
若b,p互质,并且b|a,则存在一个整数x,使得\frac{a}{b} ≡ a*x (mod p)
若b,p互质,并且b∣a,则存在一个整数x,使得ba≡a∗x(modp),
称
x
为
b
的
模
p
的
乘
法
逆
元
,
记
作
b
−
1
(
m
o
d
p
)
称x为b的模p的乘法逆元,记作b^{-1}(mod p)
称x为b的模p的乘法逆元,记作b−1(modp)
因为
a
b
≡
a
∗
b
−
1
≡
a
b
∗
b
∗
b
−
1
\frac{a}{b} ≡ a*b^{-1}≡\frac{a}{b} *b*b^{-1}
ba≡a∗b−1≡ba∗b∗b−1,所以
b
∗
b
−
1
≡
1
(
m
o
d
p
)
b*b^{-1}≡1(mod p)
b∗b−1≡1(modp)如果m是质数,且b < p ,那么由费马小定理有 ,
b
p
−
2
b^{p-2}
bp−2是b的乘法逆元。
如果只是b,p互质 , 我们也可以通过求同余方程式
b
∗
x
≡
1
(
m
o
d
p
)
b*x≡1(mod p)
b∗x≡1(modp)
现在有了乘法逆元对于除法的取模运算我们也可以适当的进行加速运算了。
线性同余方程式
定义:给定整数a,b,m,求一个整数x满足 a ∗ x ≡ b ( m o d m ) a*x ≡b(modm) a∗x≡b(modm),或者给出无解。因为未知数的指数为1,所以我们称之为一次同余方程,也称线性同余方程。
a ∗ x ≡ b ( m o d m ) a*x ≡b(modm) a∗x≡b(modm)等价于 a ∗ x − b 是 m a*x-b是m a∗x−b是m的倍数,不妨设为 − y -y −y倍。于是,该方程可以改写为 a ∗ x + m ∗ y = b a*x+m*y=b a∗x+m∗y=b。
根据Bézout定理及其证明过程,
线
性
同
余
方
程
有
解
当
且
仅
当
g
c
d
(
a
,
m
)
∣
b
线性同余方程有解当且仅当gcd(a,m)|b
线性同余方程有解当且仅当gcd(a,m)∣b。而这也证明了上面情况乘法逆元的存在性。
b
∗
x
≡
1
(
m
o
d
p
)
b*x≡1(mod p)
b∗x≡1(modp)。可以写成
b
x
+
p
y
=
1
bx + py = 1
bx+py=1因为b,p互质,所以
g
c
d
(
b
,
p
)
=
1
gcd(b,p) = 1
gcd(b,p)=1那么解一定存在。
在有解时,先用欧几里得算法求出一组整数
x
0
,
y
0
,
满
足
a
∗
x
0
+
m
∗
y
0
=
g
d
d
(
a
,
m
)
x_0,y_0,满足 a∗x_0+m∗y_0= gdd(a,m)
x0,y0,满足a∗x0+m∗y0=gdd(a,m)。然后
x
=
x
0
∗
b
/
g
c
d
(
a
,
m
)
x=x_0*b/gcd(a,m)
x=x0∗b/gcd(a,m)就是原线性同余方程的一个解。
方程的通解则是所有模m/gcd(a,m)与x同余的整数。
同余方程(数学知识+线性同余方程式)
题目转送门
解题思路
题目要求的是满足条件的最小正整数。而通解的形式是
x
0
+
k
b
x_0 + kb
x0+kb表示的是所有模b与
x
0
x_0
x0的余数相同的最小正整数。 循环来求就是
for(int i = 1 ; i <= b ; ++i)
if(i % b == (x % b +b ) % b){
cout<<i<<endl;
break;
}
不过我们发现其实我们是不用循环的,这个(x % b +b ) % b)
就是所求解。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int a , b ,x ,y;
int exgcd(int a , int b ,int & x ,int & y){
if(b == 0){
x = 1 , y = 0;
return a;
}
int d = exgcd(b , a % b , y ,x);
y -= a / b * x;
return d;
}
int main(){
cin>>a>>b;
exgcd(a,b,x,y);
cout<< (x % b + b)%b<<endl;
return 0;
}
青蛙的约会(同余+数学方程式)
解题思路
那么它们相遇的时候有方程式
a
+
m
x
≡
b
+
n
x
(
m
o
d
L
)
a + mx \equiv b+nx \quad(mod L)
a+mx≡b+nx(modL)等价于
(
a
−
b
)
+
(
m
−
n
)
x
是
L
的
倍
数
(a-b)+(m-n)x是L的倍数
(a−b)+(m−n)x是L的倍数我们假设倍数是-y倍,那么有
(
m
−
n
)
x
+
L
y
=
b
−
a
(m-n)x + Ly = b - a
(m−n)x+Ly=b−a这就是一次同余方程。那么有解当且仅当
g
c
d
(
L
,
m
−
n
)
∣
(
a
−
b
)
gcd(L,m-n) | (a-b)
gcd(L,m−n)∣(a−b)。如果有解我么用扩展欧几里得算法解出
x
0
x_0
x0后
x
=
x
0
∗
(
b
/
g
c
d
(
L
,
m
−
n
)
)
x = x_0 * (b/gcd(L,m-n))
x=x0∗(b/gcd(L,m−n))就是方程的一个特解。通解就是
X
=
x
+
L
d
,
d
=
g
c
d
(
L
,
m
−
n
)
X = x + \frac{L}{d} ,d = gcd(L,m-n)
X=x+dL,d=gcd(L,m−n),至于最小的正整数解就类似上一题所说为
(
x
m
o
d
L
d
+
L
d
)
m
o
d
L
d
(x \quad mod \quad \frac{L}{d} + \frac{L}{d})mod \frac{L}{d}
(xmoddL+dL)moddL
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL n , m , a ,b ,L , x , y;
LL exgcd(LL a , LL b ,LL & x , LL & y){
if(b == 0 ){
x = 1 , y = 0;
return a;
}
LL d = exgcd(b , a%b , y , x);
y -= a/b * x;
return d;
}
int main(){
cin>>a>>b>>m>>n>>L;
LL d = exgcd(m - n , L ,x ,y);
if((b - a) % d)cout<<"Impossible\n";
else{
x *= (b - a) / d ;
LL t = abs(L/d);
cout<< ( x % t + t) % t <<endl;
}
return 0;
}
曹冲养猪(中国剩余定理)
解题思路
这题是一个板子题,对于中国剩余定理是
中国剩余定理是构造了一组解,使得满足条件。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 11;
int n ;
int a[N] , b[N];
int 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;
}
int main(){
cin>>n;
LL m = 1;
for(int i = 1 ; i <= n ; ++i){
cin>>a[i]>>b[i];
m *= a[i];
}
LL ans = 0;
for(int i = 1 ; i <= n ; ++i){
LL x , y ;
LL M = m / a[i];
exgcd( M, a[i] , x , y);
ans += b[i] * M * x;
}
cout<<(ans % m+ m ) % m<<endl;
return 0;
}