原题链接
题目大意
给定 n , p n,p n,p求 1 ⋯ n 1\cdots n 1⋯n中所有整数在模 p p p意义下的乘法逆元。
输入格式
一行两个正整数 n , p n,p n,p。
输出格式
输出 n n n行,第 i i i行表示 i i i在模 p p p下的乘法逆元。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input
10 13
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
1
7
9
10
8
11
2
5
3
4
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
对于
3
3
3来说,他在模
13
13
13意义下的乘法逆元为
9
9
9,因为
9
9
9是最小的一个正整数解使得方程
3
x
≡
1
(
m
o
d
13
)
3x\equiv 1\pmod{13}
3x≡1(mod13)成立。
数据范围
对于
100
%
100\%
100%的数据,
1
≤
n
≤
3
×
1
0
6
,
n
<
p
<
20000528
1≤n≤3\times 10^6,n<p<20000528
1≤n≤3×106,n<p<20000528。
输入保证
p
p
p为素数。
解题思路
⚠ 警告 此题时间限制仅有500ms! { \color{#FF9100}{\rule[0pt]{2pt}{40pt}} \color{#FFF4E5}{\rule[20pt]{200pt}{20pt}} \kern{-200pt} \color{#FFFFFF}{\rule[0pt]{200pt}{20pt}} \color{orange}{\raisebox{27pt}{\kern{-195pt}{\footnotesize\bf ⚠ 警告}}} \color{black}{\raisebox{7pt}{\kern{-195pt}{\footnotesize\bf 此题时间限制仅有500ms!}}} } ⚠ 警告此题时间限制仅有500ms!
由于这恐怖的时限,所以作者这里用的是线性求逆元的方法。
定义
当 a a a与 p p p互质时,使得方程 a x ≡ 1 ( m o d p ) ax\equiv 1\pmod p ax≡1(modp)成立的最小正整数解称为 a a a在模 p p p意义下的乘法逆元,记为 a − 1 a^{-1} a−1。
解法
设
p
=
k
a
+
r
p=ka+r
p=ka+r,其中
r
=
p
m
o
d
a
,
k
=
⌊
p
a
⌋
r=p\bmod a,k=\left\lfloor\frac{p}{a}\right\rfloor
r=pmoda,k=⌊ap⌋。
则可以列出一个方程:
k
a
+
r
≡
0
(
m
o
d
p
)
ka+r\equiv 0\pmod p
ka+r≡0(modp)
两边同时乘上
a
−
1
×
r
−
1
a^{-1}\times r^{-1}
a−1×r−1,得
k
r
−
1
+
a
−
1
≡
0
(
m
o
d
p
)
kr^{-1}+a^{-1}\equiv 0\pmod p
kr−1+a−1≡0(modp)
移项,得
a
−
1
≡
−
k
r
−
1
(
m
o
d
p
)
a^{-1}\equiv -kr^{-1}\pmod p
a−1≡−kr−1(modp)
代入
r
=
p
m
o
d
a
,
k
=
⌊
p
a
⌋
r=p\bmod a,k=\left\lfloor\frac{p}{a}\right\rfloor
r=pmoda,k=⌊ap⌋,得
a
−
1
≡
−
⌊
p
a
⌋
⋅
(
p
m
o
d
a
)
−
1
a^{-1}\equiv -\left\lfloor\frac{p}{a}\right\rfloor\cdot(p\bmod a)^{-1}
a−1≡−⌊ap⌋⋅(pmoda)−1
设
i
i
i的乘法逆元为
i
n
v
i
inv_i
invi,代入原式得
a
−
1
≡
−
⌊
p
a
⌋
⋅
i
n
v
p
m
o
d
a
a^{-1}\equiv -\left\lfloor\frac{p}{a}\right\rfloor\cdot inv_{p\bmod a}
a−1≡−⌊ap⌋⋅invpmoda
由于
p
m
o
d
a
p\bmod a
pmoda一定是小于
a
a
a的,所以
i
n
v
p
m
o
d
a
inv_{p\bmod a}
invpmoda也一定会在
i
n
v
a
inv_a
inva之前出现,直接遍历一遍就可以了。
上代码
#include<cstdio>
using namespace std;
long long n,p;
long long inv[3000010];
int main()
{
scanf("%d%d",&n,&p);
inv[0]=0;
inv[1]=1;
printf("1\n");
for(int i=2; i<=n; i++)
{
inv[i]=(long long)p-(p/i)*inv[p%i]%p;
printf("%d\n",inv[i]);
}
return 0;
}
完美切题 ∼ \sim ∼