码迷,mamicode.com
首页 > 其他好文 > 详细

【模板】乘法逆元

时间:2019-01-23 23:22:17      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:输入输出格式   int   radius   space   快速   问题   ++   printf   比较   

题目背景

这是一道模板题

题目描述

给定n,p求1~n中所有整数在模p意义下的乘法逆元。

输入输出格式

输入格式:

一行n,p

输出格式:

n行,第i行表示i在模p意义下的逆元。

输入输出样例

输入样例#1: 复制
10 13
输出样例#1: 复制
1
7
9
10
8
11
2
5
3
4

说明

1n3×106,n<p<20000528

输入保证 p 为质数。

关于这道题,其实就是一个求逆元的模板题,常见的有三种方法,在这里只介绍两种方法:

1.费马小定理+快速幂(能水64分)

费马小定理:若p为素数,a为正整数,且a、p互质。 则有a^(p1)1(mod p)

又因为a*a的逆元(w)等于1,所以a^(p1)≡a*w(mod p)

故w在模p意义下是等于a^(p-2)的(记住就好)

所以问题就转化成了求a^(p-2),我们就联想到了快速幂(如果不知道什么是快速幂,我也没招)

这个算法由于快速幂的优化,时间复杂度还是比较可观的,基本可以稳定在(nlogn)

附上该方法的代码:

 1 #include<cstdio>
 2 using namespace std;
 3 long long p;
 4 long long qpow(long long x,long long y)
 5 {
 6     long long ans=1;
 7     while(y!=0)
 8     {
 9         if(y&1)
10         {
11             ans=((ans%p)*(x%p))%p;
12         }
13         x=((x%p)*(x%p))%p;
14         y>>=1;
15     }
16     return ans;
17 }
18 int main()
19 {
20     long long n;
21     scanf("%lld%lld",&n,&p);
22     for(register int i=1;i<=n;i++)
23     {
24         printf("%lld\n",(qpow(i,p-2))%p);
25     }
26     return 0;
27 }

 

2.线性递推(100分O(n)的神级算法)

令 p=ki+r k=p/i?⌋,r=moi (i<p,k<p,r<i)

那么显然 ki+r≡0(mod p)  

我们将左右同时乘以i和r的逆元即可得到

kr^1+i^10(modp)

i^1kr^1(modp)

代入k和r

i^1⌊p/i(mod i)^-1   (modp)

由于逆元一定是整数,那么我们在等式左右同时乘以(mod i)^-1倍的p,由于在模p意义下,等式依然成立

最终状态:

inv[i] = (p - p / i) * inv[p % i] % p;(inv指逆元)

附上本算法的代码:

 1 #include<cstdio>
 2 using namespace std;
 3 long long p,c[3000005];
 4 int main()
 5 {
 6     long long n;
 7     scanf("%lld%lld",&n,&p);
 8     c[1]=1;
 9     printf("1\n");
10     for(register int i=2; i<=n; i++)
11     {
12         c[i]=(p-p/i)*c[p%i]%p;
13         printf("%lld\n",c[i]);
14     }
15     return 0;
16 }

 

【模板】乘法逆元

标签:输入输出格式   int   radius   space   快速   问题   ++   printf   比较   

原文地址:https://www.cnblogs.com/yufenglin/p/10311891.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!