本蒟蒻第一次讲课,由于比较匆忙所以没有及时准备课件,在此表示抱歉…
听说他们讲课都是啥都没有 在那儿唠嗑
20
20
20分钟然后问:有没有不会的 不会的自己学 就完事了??
2333
2333
2333真是负责
前景提要
这是一篇数论 0 0 0零起点到负无穷,从入门到入土的博客 请大家做好心理准备
听说
C
C
C层要讲数论?
哈 作为前数学竞赛生的我当然要抢着讲了 于是跟
p
j
t
pjt
pjt大哥蹭了一下
本着放松随便讲一讲的心态 我问了我们这边的
l
y
s
s
lyss
lyss小宝宝
但是 p j t pjt pjt去自由啊…那就我自己写吧…
t i p s : tips: tips:现在要讲的基本涉及的都是整数 所用的字母除声明外也都表示整数
P a r t 1. Part1. Part1.整数的常识
一、整除
1.设
a
a
a、
b
b
b是给定的数
,
b
≠
0
,b\neq0
,b=0。若存在整数
c
,
c,
c,使得
a
=
b
c
,
a=bc,
a=bc,则称
b
b
b整除
a
,
a,
a,记作
b
∣
a
,
b\mid a,
b∣a,反之
,
,
,则称
b
b
b不能整除
a
,
a,
a,记作
b
∤
a
b\nmid a
b∤a。
2.一些性质:
a. 若
a
∣
b
a|b
a∣b,且
b
∣
c
b|c
b∣c,则
a
∣
c
a|c
a∣c。
b. 若
b
∣
a
b|a
b∣a,且
b
∣
c
b|c
b∣c,则
b
∣
(
a
±
c
)
b|(a\pm c)
b∣(a±c)
c.若
c
∣
a
c|a
c∣a,且
c
∣
b
c|b
c∣b,则对于任意整数m、n,有
c
∣
(
m
a
+
n
b
)
c|(ma+nb)
c∣(ma+nb)。
二、素数与合数
\,\,\,\,\,\,\,\, 对于一个正整数,如果它有且仅有1和它自己两个约数,那么我们称这个数为素数。如果有两个以上的约数,那么我们称这个数为合数。注意:1既不是素数也不是合数
先植入一个没什么用的定理,它叫素数定理:
小于x的素数的个数近似等于x/ln(x)…
现在我们想想如何求素数
1.考虑暴力枚举
如果
2
−
n
2 -\sqrt{n}
2−n每个数都不是
n
n
n的因子,那么
n
n
n就是质数了。
复杂度
O
(
n
)
O(\sqrt{n})
O(n)
那么我们来看一道题:
求
1
−
n
1-n
1−n内的素数。
n
<
=
1000000
n<=1000000
n<=1000000
用上述的算法那是要跑 100 s 100s 100s的 所以我们就需要换一个高效的算法
2.筛法求素数
基本思路是:素数的倍数不是素数
\,\,\,\,\,\,\,\,
1不是素数首先把它筛掉,剩下的数中最小的数一定是素数,然后去掉它的倍数。
v
i
s
[
i
]
vis[i]
vis[i]表示
i
i
i是否被访问过
,
c
n
t
,cnt
,cnt表示现在素数的数量
,
p
r
i
m
e
,prime
,prime数组存的是从小到大的素数
代码:
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i;
for(int j=1;j*i<=n;j++)vis[i*j]=true;
}
}
这回由
O
(
n
n
)
O(n\sqrt{n})
O(nn)变成了
O
(
n
l
o
g
n
)
O(n\,log_n)
O(nlogn)了
但是我们注意到,这样筛会筛重很多次。
我们拿
75
75
75举例 :在筛到素数
3
3
3时我们把它筛除 在筛到素数
5
5
5时我们又会筛除一次 这样会浪费大量的时间,如何优化呢?
3.线性筛
基本思路是:在筛法的基础上 我们让每一个合数只能被他自己最小的素数筛到
如何实现这个优化呢?
看代码
for(int i=2;i<=n;i++){
if(!vis[i])prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vis[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
在筛到每个数时 我们把小于它的最小质数的所有质数倍数的数都筛掉 这样就能保证每个数是被它自己最小的质因子筛掉
P a r t 2. Part2. Part2. g c d & l c m gcd\&lcm gcd&lcm
g c d gcd gcd是啥? l c m lcm lcm是啥?某党?
g
c
d
gcd
gcd指的是
g
r
e
a
t
e
s
t
c
o
m
m
o
n
d
i
v
i
s
o
r
greatest\,\,common\,\, divisor
greatestcommondivisor就是最大公约数。
l
c
m
lcm
lcm指的是
L
e
a
s
t
C
o
m
m
o
n
M
u
l
t
i
p
l
e
,
Least\,\,Common\,\,Multiple,
LeastCommonMultiple,即最小公倍数。
一、最大公约数
最大公约数是数论中一个重要的概念
设
a
a
a、
b
b
b不全为零
,
,
,同时整除
a
a
a、
b
b
b的整数称为他们的公约数
,
,
,显然
a
a
a、
b
b
b的公约数只有有限多个
,
,
,我们将其中最大的一个称为
a
a
a、
b
b
b的最大公约数表示
,
,
,用符号
(
a
,
b
)
(a,b)
(a,b)表示。显然
,
,
,最大公约数是一个正整数。
当
(
a
,
b
)
=
1
(a,b)=1
(a,b)=1时
,
,
,我们称
a
a
a与
b
b
b互质
(
(
(互素
)
,
),
),这种情形特别重要。
那么问题来了 我们怎么求最大公约数呢?
通常用辗转相除法来写 我的个人喜好是用递归
辗转相除法是不都会…? 算了算了 好好讲讲吧
我们可以很显然地理解这个等式:
g c d ( a , b ) = g c d ( a − b , b ) gcd(a,b)=gcd(a-b,b) gcd(a,b)=gcd(a−b,b)
但是呢 这么一次一次减太慢了 所以我们一次能减多少就减多少
就相当于直接除 这就是简述版的辗转相除
int gcd(int a, int b){
if(b==0)return a;
else return gcd(b,a%b);
}
我不会告诉你们algorithm库里有可以直接用的__gcd
辗转相除在后面个的扩展
g
c
d
gcd
gcd中还是很有用的
上两个题吧
luoguP1372
简述版题意:给你个
n
n
n和
k
k
k 求
n
n
n个数中取
k
k
k个的最大公约数最大
S
o
l
u
t
i
o
n
:
Solution:
Solution:设这
k
k
k个数的最大公约数为
g
c
d
gcd
gcd
则第
k
k
k个数最小为
k
×
g
c
d
k×gcd
k×gcd 所以
k
×
g
c
d
≤
n
k×gcd\leq n
k×gcd≤n
那么
g
c
d
≤
n
k
gcd\leq\frac{n}{k}
gcd≤kn 显然最大的
g
c
d
=
⌊
n
k
⌋
gcd=\lfloor\frac{n}{k}\rfloor
gcd=⌊kn⌋
#include<iostream>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
cout<<n/k<<endl;
}
luoguP2090
对于一个数字对(a, b),我们可以通过一次操作将其变为新数字对(a+b, b)或(a, a+b)。
给定一正整数n,问最少需要多少次操作可将数字对(1, 1)变为一个数字对,该数字对至少有一个数字为n。
S
o
l
u
t
i
o
n
:
Solution:
Solution:
注意到等式
g
c
d
(
a
,
b
)
=
g
c
d
(
a
,
a
+
b
)
gcd(a,b)=gcd(a,a+b)
gcd(a,b)=gcd(a,a+b)
所以找到
1
1
1到
n
−
1
n-1
n−1中
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)递归层数最少的就好咯
在这儿推一下那天的模拟赛的解题报告 其中就有这道题 模拟赛不是很难大家可以看看
最后有彩蛋哦
地址在这!:题解
#include<bits/stdc++.h>
using namespace std;
#define inf int(1e8)
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
int gcdd(int a, int b){
if(!b)return inf;
if(b==1)return a-1;
return gcdd(b,a%b)+a/b;
}
int n,now=inf;
int main(){
read(n);
for(int i=1;i<=(n+1)/2;i++)now=min(now,gcdd(n,i));
printf("%d\n",now);
}
二、最小公倍数
那么我们再简单地谈谈最小公倍数
设
a
、
b
a、b
a、b是两个非零正整数
,
,
,一个同时为
a
、
b
a、b
a、b的倍数的书称为他们的一个公倍数
,
,
,两个数的公倍数显然有无穷多个
,
,
,我们把这其中的最小的正整数称为他们的最小公倍数
那最小公倍数就很好求了
l c m ( a , b ) = a b g c d ( a , b ) lcm(a,b)=\frac{ab}{gcd(a,b)} lcm(a,b)=gcd(a,b)ab
U
P
D
:
UPD:
UPD:昨天讲到这里哦!
经过一 天
P a r t 3. Part3. Part3.同余及应用
一、同余
同余是数论中的一个重要概念,应用极为广泛。
设
n
n
n是给定的正整数,若整数
a
、
b
a、b
a、b满足
n
∣
(
a
−
b
)
,
n\mid(a-b),
n∣(a−b),则称
a
a
a和
b
b
b模
n
n
n同余
,
,
,记作
a ≡ b ( m o d n ) a\equiv b(mod\,\,n) a≡b(modn)
反之,则称 a a a与 b b b模 n n n不同余 , , ,记作
a ≢ b ( m o d n ) a\not\equiv b(mod\,\,n) a≡b(modn)
很显然, a a a 和 b b b模 n n n同余的充分必要条件是 a a a与 b b b被 n n n除得的余数相同。
同余式的几个性质:
- 反身性: a ≡ a ( m o d n ) a\equiv a(mod\,\,n) a≡a(modn)
- 对称性:若 a ≡ b ( m o d n ) , a\equiv b(mod\,\,n), a≡b(modn),则 b ≡ a ( m o d n ) b\equiv a(mod\,\,n) b≡a(modn)
- 传递性:若 a ≡ b ( m o d n ) , a\equiv b(mod\,\,n), a≡b(modn), b ≡ c ( m o d n ) , b\equiv c(mod\,\,n), b≡c(modn),则 a ≡ c ( m o d n ) a\equiv c(mod\,\,n) a≡c(modn)
- 可加性:若 a ≡ b ( m o d n ) , a\equiv b(mod\,\,n), a≡b(modn), c ≡ d ( m o d n ) , c\equiv d(mod\,\,n), c≡d(modn),则 a ± c ≡ b ± d ( m o d n ) a\pm c\equiv b\pm d(mod\,\,n) a±c≡b±d(modn)。
- 若
a
≡
b
(
m
o
d
n
)
,
a\equiv b(mod\,\,n),
a≡b(modn),
c
≡
d
(
m
o
d
n
)
,
c\equiv d(mod\,\,n),
c≡d(modn),则
a
c
≡
b
d
(
m
o
d
n
)
ac\equiv bd(mod\,\,n)
ac≡bd(modn)。
运用这几个性质 我们把同余应用在信息中的数论
二、快速幂
给定
a
、
n
、
m
a、n、m
a、n、m求
a
n
m
o
d
k
a^n\,\,mod\,\,k
anmodk
考虑朴素算法 用循环一个一个累乘 可以在
O
(
n
)
O(n)
O(n)的时间内求出答案
不过似乎没什么用 这一点都不快速
那么我们来点快的
考虑到
a
2
n
=
a
n
2
a^{2n}={a^n}^{2}
a2n=an2所以我们可以两两配对地乘
所以
1.
1.
1.当n是奇数时,那么有
a
n
=
a
∗
a
n
−
1
a^{n} = a * a^{n-1}
an=a∗an−1
2.
2.
2.当n是偶数时,那么有
a
n
=
a
n
2
∗
a
n
2
a^n = a^\frac{n}{2}* a^\frac{n}{2}
an=a2n∗a2n
上代码
int quickpow(int a, int n, int m){
int ret=1;
while(b){
if(b&1)(ret*=a)%=m;
(a*=a)%=m,n>>=1;
}
}
时间复杂度:
O
(
l
o
g
n
)
O(log_n)
O(logn)
10.23
23
:
12
10.23\,\,\,23:12
10.2323:12今天先写到这儿 明天应该讲不到这儿
三、扩展欧几里得
引题:给定
a
、
b
、
c
,
a、b、c,
a、b、c,求使得
a
x
+
b
y
=
c
ax+by= c
ax+by=c成立的最小正整数解
x
、
y
,
x、y,
x、y,如果无解则输出
l
y
s
w
a
n
lyswan
lyswan
讲真的 我是从这个题开始认识到信息真的是一门竞赛…
S
o
l
u
t
i
o
n
:
Solution:
Solution:
1.
1.
1.首先考虑是否有解:当
g
c
d
(
a
,
b
)
∣
c
gcd(a,b)\mid c
gcd(a,b)∣c时方程才有解
2.
2.
2.所以我们先不管
c
c
c到底是
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)的几倍 直接给
我们考虑如何搞这个方程:
首先看这个方程:
b
x
+
(
a
%
b
)
y
=
c
bx+(a\%b)y= c
bx+(a%b)y=c这样以此类推
最后会得到
g
c
d
(
a
,
b
)
x
=
c
gcd(a,b)x= c
gcd(a,b)x=c此时
x
=
1
x=1
x=1
对于
a
′
=
b
,
b
′
=
a
%
b
a' = b, b' = a\% b
a′=b,b′=a%b而言,我们求得
x
,
y
x, y
x,y使得
a
′
x
+
b
′
y
=
g
c
d
(
a
′
,
b
′
)
,
a'x + b'y = gcd(a', b'),
a′x+b′y=gcd(a′,b′), 由于
b
′
=
a
%
b
=
a
−
⌊
a
b
⌋
×
b
b' = a \% b = a - \lfloor\frac{a}{b}\rfloor ×b
b′=a%b=a−⌊ba⌋×b
所以可以推得
a
y
+
b
(
x
−
⌊
a
b
⌋
×
y
)
=
g
c
d
(
a
,
b
)
ay +b(x - \lfloor\frac{a}{b}\rfloor ×y) = gcd(a, b)
ay+b(x−⌊ba⌋×y)=gcd(a,b)
即一组通解为
x
=
y
,
y
=
x
−
⌊
a
b
⌋
×
y
x=y,y=x - \lfloor\frac{a}{b}\rfloor ×y
x=y,y=x−⌊ba⌋×y
问题来了 我们怎么用代码实现呢?
注意到我们方程的变形用的是
g
c
d
gcd
gcd函数辗转相除,方程的通解是一步一步递归才能得到 所以用递归版的欧几里得顺便求得。
这个就叫扩展欧几里得 上代码:
void extended_gcd(int a, int b, int &x, int &y){
if(b==0){x=1,y=0;return;}
extended_gcd(b,a%b,x,y);
int t=y;
y=x-(a/b)*y,x=t;
}
最后的 x , y x,y x,y就是解 不过出来可能会是一个负数 求最小正整数解还要再加上一个 m o d mod mod
这个东西其实真的很有用的 我们看一道题
N
O
I
P
2012
NOIP2012
NOIP2012同余方程
题意:求关于
x
x
x的同余方程
a
x
≡
1
(
m
o
d
b
)
a x \equiv 1 \pmod {b}
ax≡1(modb)的最小正整数解。
S
o
l
u
t
i
o
n
:
Solution:
Solution:转化为
a
x
+
b
y
=
1
ax+by=1
ax+by=1 就变成了扩展欧几里得…
代码:
#include<cstdio>
int t,c,d,x,y;
void exgcd(int a, int b, int &x, int &y)
{
if(a%b==0)
{
x=0;
y=1;
return;
}
exgcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
}
int main()
{
scanf("%d%d",&c,&d);
exgcd(c,d,x,y);
while(x<=0)
{
x+=d;
}
printf("%d\n",x);
}
四、欧拉函数
欧拉函数,即
φ
(
x
)
φ(x)
φ(x),简单说它表示从
1
−
n
1-n
1−n中和它互质的数的个数
欧拉函数在各种玄学定理中经常出现,有的题中
g
c
d
=
1
gcd=1
gcd=1 的情形往往可以转化为欧拉函数
如何求欧拉函数
1.
1.
1.单个数欧拉函数的求解公式:
对于一个数
x
=
∏
i
=
1
n
p
i
α
i
,
x=\prod \limits_{i=1}^{n} p_{i}^{\alpha _i},
x=i=1∏npiαi,那么
φ
(
x
)
=
x
∏
i
=
1
n
(
1
−
1
p
i
)
φ(x)=x\prod \limits_{i=1}^n (1-\frac{1}{p_i})
φ(x)=xi=1∏n(1−pi1)
至于为啥有兴趣的自己推 不难推,这里就不赘述了。主要是…我现在要码不完了啊啊估计明天也讲不完了所以直接过吧…求饶
.
j
p
g
.jpg
.jpg
2.
2.
2. 线性求
1
−
n
1-n
1−n 所有数的欧拉函数
(
(
(即欧拉筛
)
)
)
上述求解欧拉函数不是没有用 实在是太磨叽…又要分解质因数,又要求乘积,还有分数…没看我代码都没给吗2333 但有时候这个式子推一些性质很有用的
我们欧拉筛之前先要了解几个性质:
a
.
a.
a.对于质数
p
p
p,有
φ
(
p
)
=
p
−
1
φ(p)=p-1
φ(p)=p−1 显然…
b
.
b.
b.当
(
n
,
m
)
=
1
(n,m)=1
(n,m)=1时,有
φ
(
n
×
m
)
=
φ
(
n
)
×
φ
(
m
)
(
φ(n×m)=φ(n)×φ(m)(
φ(n×m)=φ(n)×φ(m)(即欧拉函数是但不完全是积性函数
)
)
),特别地,当
2
∤
n
2\nmid n
2∤n时,
φ
(
2
n
)
=
φ
(
n
)
φ(2n)=φ(n)
φ(2n)=φ(n)。
用上面的定义式这个显然成立
c
.
c.
c.当
m
∣
n
m\mid n
m∣n时,
φ
(
m
×
n
)
=
m
×
φ
(
n
)
φ(m×n)=m×φ(n)
φ(m×n)=m×φ(n)。
用定义式回去自己推不会问我…
那么这些性质我们了解之后,就可以筛筛筛筛筛筛了
首先想一想 上面的性质是不是有点眼熟?
p
p
p 为质数,
n
%
m
=
0
n\%m=0
n%m=0?
没错就是线性筛,我们可以在线性筛素数的时候,运用这三条性质来维护欧拉函数,具体看代码 我要讲不完了!!
euc[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])euc[i]=i-1,prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(i*prime[j]>n)break;
vis[i*prime[j]]=true;
if(i%prime[j]==0)
{
euc[i*prime[j]]=euc[i]*prime[j];
break;
}
else euc[i*prime[j]]=euc[i]*euc[prime[j]];
}
}
仔细体会其实不难
上例题:
题面找不到了 大哥们我错了
题意:给定
n
n
n,求
1
≤
x
,
y
≤
n
1\leq x,y\leq n
1≤x,y≤n且
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1的数对个数
这就用到我们前面讲的 某些问题的
g
c
d
=
1
gcd=1
gcd=1可以转化为欧拉函数
用式子写出来就是:
∑
i
=
1
n
∑
j
=
1
n
(
g
c
d
(
i
,
j
)
=
1
)
\sum_{i=1}^n \sum_{j=1}^n (gcd(i,j)=1)
∑i=1n∑j=1n(gcd(i,j)=1)
=
∑
i
=
1
n
φ
(
i
)
=\sum_{i=1}^nφ(i)
=∑i=1nφ(i)
所以只需要求出欧拉函数的前缀和即可
五、逆元
终于来到最有用的地方了…
什么是逆元?
对于一个数
x
,
x,
x,它在模
p
p
p意义下的逆元
a
a
a,满足
a
x
≡
1
(
m
o
d
p
)
,
ax\equiv 1\pmod p,
ax≡1(modp),
这东西很有用 可以说没有逆元数论少了灵魂
看这个题:给定
n
,
m
,
p
n,m,p
n,m,p求
n
m
m
o
d
p
\frac{n}{m}mod\,\,p
mnmodp
如果你没学逆元 你肯定懵逼:
w
o
c
?
?
woc??
woc??分数还能取模?
这就是逆元的妙处
S
o
l
u
t
i
o
n
:
Solution:
Solution:求出
m
m
m在模
p
p
p意义下的逆元
a
a
a,答案为
n
a
%
p
na\%p
na%p。
那么这么好用的一个东西 我们怎么求呢???
求逆元的方法
1.
1.
1.
e
x
g
c
d
exgcd
exgcd
逆元满足什么条件?
a
x
≡
1
(
m
o
d
p
)
ax\equiv 1\pmod p
ax≡1(modp)?同余方程啊!
e
x
g
c
d
exgcd
exgcd显然可行啊。
性能分析:
- 时间复杂度 O ( l o g m a x ( a , b ) ) O(log_{max(a,b)}) O(logmax(a,b)) 不是太差
- 适用范围:只要存在逆元就可求,适用个数不多,当
m
o
d
mod
mod很大很大时是个非常不错
唯一的选择 - 缺点:递归~讨厌厌…这是最常见以及我最不愿意打的一个…
2.
2.
2.快速幂
快速幂怎么求逆元?
那首先你需要了解一个定理—费马小定理:
若 p p p为素数,那么 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p ap−1≡1(modp)
这个是怎么来的呢? 欧拉定理的推论
欧拉定理(有时也叫作费马小定理的一般式):
a φ ( p ) ≡ 1 ( m o d p ) a^{φ(p)}\equiv 1\pmod p aφ(p)≡1(modp)
那欧拉定理怎么来的呢?有兴趣自己查查(其实是来不及了!!
接着说 因为
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p-1}\equiv 1\pmod p
ap−1≡1(modp),所以
a
p
−
2
a^{p-2}
ap−2就是
a
a
a的逆元
性能分析:
- 时间复杂度: O ( l o g m o d ) O(log_{mod}) O(logmod)
- 适用范围:在 m o d mod mod是素数!! 并且 m o d mod mod不是太太太大大大的时候
- 优点:比扩欧好写,我最喜欢求逆元的方法之一
- 缺点:如果 m o d mod mod是合数相信没有人无聊到筛一遍欧拉函数
3.
3.
3. 线性求逆元
放心放心 这次线性没有筛 不用害怕
原理:
p
p
p是模数,我们现在要求的是
i
i
i的逆元
将
p
p
p写成
p
=
k
∗
i
+
r
p=k∗i+r
p=k∗i+r其中
0
<
r
<
i
0<r<i
0<r<i(就是带余除法)
则
k
=
p
i
,
r
=
p
%
i
k=\frac{p}{i},r=p\%i
k=ip,r=p%i
解释一下 第二行是第一行两边都除
i
r
ir
ir得到的
总的来说就是一个公式:
i
n
v
[
i
]
=
−
(
m
o
d
/
i
)
∗
i
n
v
[
m
o
d
%
i
]
inv[i]=-(mod/i)*inv[mod\%i]
inv[i]=−(mod/i)∗inv[mod%i]边界是
i
n
v
[
1
]
=
1
inv[1]=1
inv[1]=1
优点:
a
.
a .
a.在
O
(
n
)
O(n)
O(n)的时间内求出
1
−
n
1-n
1−n 的所有逆元 高效
b
.
b.
b.代码好打 就一行
c
.
c.
c.没有缺点
代码:
inv[1]=1;
for(int i=2;i<mod;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
回到前面的问题,现在我们会求逆元了,分数取模自然也就很水了
有理数取余
题意:给出一个有理数
c
=
a
b
c=\frac{a}{b}
c=ba,求
c
m
o
d
19260817
c\ \bmod 19260817
c mod19260817c的值。
S
o
l
u
t
i
o
n
:
Solution:
Solution:直接求
b
b
b的逆元,由于19260817是个质数,所以输出
a
×
b
m
o
d
−
2
a×b^{mod-2}%mod
a×bmod−2就好了,由于
a
,
b
a,b
a,b很大 所以需要处理一下:↓
#include<cstdio>
typedef long long ll;
const ll mod=19260817;
ll quickpow(ll a, ll b){
ll ret=1;
while(b){
if(b&1)(ret*=a)%=mod;
(a*=a)%=mod,b>>=1;
}
return ret;
}
ll n,m;
ll getint(){
char chr=getchar();ll x=0;
while(chr<'0'||chr>'9')chr=getchar();
while(chr>='0'&&chr<='9'){
x=(x*10)%mod;
chr=getchar();
}
return x;
}
int main(){
n=getint(),m=getint();
if(m==0)return printf("Angry!"),0;
printf("%lld\n",n*quickpow(m,mod-2)%mod);
}
板子题
题意:给定
n
,
p
n,p
n,p求
1
−
n
1-n
1−n中所有整数在模
p
p
p意义下的乘法逆元。
S
o
l
u
t
i
o
n
:
Solution:
Solution:没有
S
o
l
u
t
i
o
n
Solution
Solution,线性求逆元直接过
#include<bits/stdc++.h>
#define N 3000010
typedef long long ll;
using namespace std;
int inv[N],n,p;
inline int read(){
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();};
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch&15);ch=getchar();};
return f*x;
}
int main(){
n=read();p=read();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]);
}
}
逆元是一种非常有用的工具 它可以和很多有用的定理结合在一起形成扩展定理
六、中国剩余定理
中国剩余定理,也称孙子定理,话说昨天你们为什么对这个定理这么感兴趣呢…?
中国剩余定理能干啥呢?
比如 一筐苹果 三个三个吃最后剩两个,四个四个吃最后剩三个,五个五个吃最后剩四个,求一共有多少个苹果?
答案是
59
59
59个.
当然中国剩余定理不只这么简单
给定
k
k
k以及
k
k
k个
a
i
、
m
i
a_i、m_i
ai、mi求一个最小的正整数
n
n
n满足
{
n
≡
a
1
(
m
o
d
m
1
)
n
≡
a
2
(
m
o
d
m
2
)
.
.
.
n
≡
a
k
(
m
o
d
m
k
)
\begin{cases} n\equiv a_1(\mod m_1)\quad \\ n\equiv a_2(\mod m_2)\quad \\... \\ n\equiv a_k(\mod m_k)\quad \ \end{cases}
⎩
⎨
⎧n≡a1(modm1)n≡a2(modm2)...n≡ak(modmk)
其中
(
m
1
,
m
2
,
.
.
.
,
m
k
)
=
1
(m_1,m_2,...,m_k)=1
(m1,m2,...,mk)=1
如何求解呢?
令
M
=
∏
i
=
1
k
m
i
M=\prod_{i=1}^km_i
M=∏i=1kmi,即
M
M
M是所有
m
i
m_i
mi 的最小公倍数
对于每个方程,设
p
i
=
M
m
i
p_i=\frac{M}{m_i}
pi=miM
t
i
t_i
ti为同余方程
p
i
t
i
≡
1
(
m
o
d
m
i
)
p_it_i\equiv 1(mod\,\,m_i)
piti≡1(modmi)的最小非负整数解
则有一个解
x
=
∑
i
=
1
k
a
i
M
m
i
t
i
x=\sum_{i=1}^ka_i\frac{M}{m_i}t_i
x=∑i=1kaimiMti
通解为
x
+
i
∗
M
(
i
∈
Z
)
x+i∗M(i∈Z)
x+i∗M(i∈Z)
特别地,最小非负整数解为
(
x
%
M
+
M
)
%
M
(x\%M+M)\%M
(x%M+M)%M
自己推推 很好理解 盲猜时间应该不够了 所以不讲了 不会问我
代码实现:求
t
i
t_i
ti那个同余方程时要用到扩展欧几里得
其他的…入门难度的代码实现
void ex_gcd(ll n, ll m, ll &x, ll &y){
if(!m){x=1,y=0;return;}
ex_gcd(m,n%m,y,x);y-=(n/m)*x;
}
ll CRT(){
ll ans=0,lcm=1,x,y;
for(int i=1;i<=k;i++)lcm*=b[i];
for(int i=1;i<=k;i++){
t[i]=lcm/b[i];
ex_gcd(t[i],b[i],x,y);
x=(x%b[i]+b[i])%b[i];
ans=(ans+t[i]*a[i]%lcm*x%lcm)%lcm;
}
return (ans+lcm)%lcm;
}
例题例题例题:
T
J
O
I
2009
TJOI2009
TJOI2009猜数字
简述题意:给个
t
t
t,
t
t
t组数据,每组数据给
k
k
k以及
k
k
k个
a
i
、
m
i
a_i、m_i
ai、mi求最小的非负整数
n
n
n,满足对于任意的
i
,
n
−
a
i
i,n - a_i
i,n−ai能被
b
i
b_i
bi整除。
S
o
l
u
t
i
o
n
:
Solution:
Solution:板子题板子题板子题!!!
从这个:
推到这个:
即:
题中给的
(
b
1
,
b
2
,
.
.
.
,
b
k
)
=
1
(b_1,b_2,...,b_k)=1
(b1,b2,...,bk)=1所以中国剩余定理可做。
注意:
1.
1.
1.直接乘爆
l
o
n
g
l
o
n
g
long long
longlong要用快速乘,快速乘其实是慢速乘…具体跟快速幂差不多,看代码
2.
2.
2.直接快速乘会
T
L
E
TLE
TLE因为快速乘不能有负数,而题中说数可能为负数,所以如果是负数要加个
m
o
d
mod
mod…
这两个地方当时差点没坑死我…
代码↓
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll quickpow(ll x, ll y, ll mod){
ll ret=1;
while(y){
if(y&1)(ret*=x)%=mod;
(x*=x)%=mod,y>>=1;
}
return ret;
}
inline ll quickmul(ll x, ll y, ll mod){
if(x<0)x+=mod;if(y<0)y+=mod;
if(y>x)swap(x,y);
ll ret=0;
while(y){
if(y&1)(ret+=x)%=mod;
(x+=x)%=mod,y>>=1;
}
return ret;
}
ll k,a[20],b[20],t[20];
void ex_gcd(ll n, ll m, ll &x, ll &y){
if(!m){x=1,y=0;return;}
ex_gcd(m,n%m,y,x);y-=(n/m)*x;
}
ll CRT(){
ll ans=0,lcm=1,x,y;
for(int i=1;i<=k;i++)lcm*=b[i];
for(int i=1;i<=k;i++){
t[i]=lcm/b[i];
ex_gcd(t[i],b[i],x,y);
x=(x%b[i]+b[i])%b[i];
ans=(ans+quickmul(quickmul(t[i],a[i],lcm),x,lcm))%lcm;
}
return (ans+lcm)%lcm;
}
int main(){
scanf("%lld",&k);
for(int i=1;i<=k;i++)scanf("%lld",&a[i]);
for(int i=1;i<=k;i++)scanf("%lld",&b[i]);
printf("%lld\n",CRT());
}
此外,当模数不是互质时,我们就会用到扩展中国剩余定理了,有兴趣的可以自己学一下
P a r t 4. Part4. Part4.组合数学
组合数学是信息中的数论的一个重要分支
不过讲不完了
加我
Q
Q
:
407694747
QQ:407694747
QQ:407694747免费一对一辅导,不容错过…