题目
这是一道模板题
题目描述
给定 n,p求1∼nn,p求 1\sim nn,p求1∼n中所有整数在模 ppp 意义下的乘法逆元。
输入格式
一行两个正整数 n,pn,pn,p。
输出格式
输出 nnn 行,第 iii 行表示 iii 在模 ppp 下的乘法逆元。
输入输出样例
输入
10 13
输出
1
7
9
10
8
11
2
5
3
4
说明/提示
1≤n≤3×106,n<p<200005281 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528
输入保证 ppp 为质数。
题解
模板乘法逆元
可把刚打好的扩欧乘法逆元板子交上去结果发现 T 了,
看了眼题解才发现要用线性方法求逆元,因为题目要求1~n的逆元。
线性法要推导一个递推公式:
设 p=k∗i+rp=k*i+rp=k∗i+r
也就是说 p/ip/ip/i 的商为 kkk,余数为 rrr。
∴k=⌊pi⌋, r=p mod i\therefore k=⌊ \frac{p}{i} ⌋, \ r=p\; mod\; i∴k=⌊ip⌋, r=pmodi
得 k∗i+r≡0 (mod p)k*i+r\equiv0\ \ (mod\ \ p)k∗i+r≡0 (mod p)
左右同乘 (i−1∗r−1)(i^{-1}*r^{-1})(i−1∗r−1), \;\;\;\;\;\;\;// x−1x^{-1}x−1 表示 x 的逆元
得:k∗r−1+i−1≡0 (mod p)k*r^{-1}+i^{-1}\equiv0\ \ (mod\ \ p)k∗r−1+i−1≡0 (mod p)
代入k=⌊pi⌋, r=p mod ik=⌊\frac{p}{i}⌋, \ r=p\; mod\; ik=⌊ip⌋, r=pmodi
得: ⌊pi⌋∗(p mod i)−1+i−1≡0 (mod p)⌊ \frac{p}{i}⌋*(p\; mod\; i)^{-1}+i^{-1}\equiv0\ \ (mod\ \ p)⌊ip⌋∗(pmodi)−1+i−1≡0 (mod p)
∴i−1≡−⌊pi⌋∗(p mod i)−1 (mod p)\therefore i^{-1}\equiv-⌊ \frac{p}{i}⌋*(p\; mod\; i)^{-1}\ \ (mod\ \ p)∴i−1≡−⌊ip⌋∗(pmodi)−1 (mod p)
∴i−1 % p=−⌊pi⌋∗(p % i)−1 % p\therefore i^{-1}\;\%\;p=-⌊ \frac{p}{i}⌋*(p\;\%\; i)^{-1}\;\%\;p∴i−1%p=−⌊ip⌋∗(p%i)−1%p
∴i−1=−⌊pi⌋∗(p % i)−1 % p \therefore i^{-1}=-⌊ \frac{p}{i}⌋*(p\;\%\; i)^{-1}\;\%\;p\;\;\;\;\;∴i−1=−⌊ip⌋∗(p%i)−1%p ( i 的逆元必小于 p,所以左边模 p可省掉)
所以我们便有了个递推式:
inv[i]=−p/i∗inv[p % i] % pinv[i]=-p/i*inv[p\ \%\;i]\;\%\; pinv[i]=−p/i∗inv[p %i]%p
∵p%p 等于0\because p\%p\;等于0∵p%p等于0
∴inv[i]=p−p/i∗inv[p % i] % p 加上p答案不变\therefore inv[i]=p-p/i*inv[p\ \%\;i]\;\%\; p\;\;\;\;\;\;\;\;\;\;\;\;加上p答案不变∴inv[i]=p−p/i∗inv[p %i]%p加上p答案不变
这样就能保证 inv[i]>0inv[i]>0inv[i]>0
超级简洁的代码
#include<iostream>
using namespace std;
long long p,n,inv[10000001];
int main()
{
scanf("%d%d",&n,&p);
inv[1]=1; //初始化,1在所有意义下的逆元都为1
for(int i=2; i<=n; i++) inv[i]=(-p/i)*inv[p%i]%p; //从2开始套式子递推
for(int i=1; i<=n; i++) printf("%d\n",inv[i]); //最后输出
return 0;
}
博客围绕一道模板题展开,要求给定n、p求1~n中所有整数在模p意义下的乘法逆元。常规扩欧乘法逆元方法会超时,需用线性方法。推导得出递推公式inv[i]= -p/i * inv[p %i] %p,还给出保证结果为正的优化公式。
413

被折叠的 条评论
为什么被折叠?



