P5431 【模板】乘法逆元2

该博客介绍了一种利用费马小定理和快速幂计算模逆元的简单方法,适用于处理大量数据。通过先边读入边通分,然后应用费马小定理的性质x=ap−2,可以高效地计算出每个数的模逆元,并最终求出给定数列在模p意义下的乘积逆元。代码中展示了如何实现这一过程。

题目

给定 n 个正整数 a i a_i ai,求它们在模 p p p 意义下的乘法逆元。
由于输出太多不好,所以将会给定常数 k k k,你要输出的答案为:
∑ i = 1 n k i a i \sum\limits_{i=1}^n\frac{k^i}{a_i} i=1naiki
当然要对 p 取模。

输入格式

第一行三个正整数 n,p,k 意义如题目描述。
第二行 n 个正整数 a_i ,是你要求逆元的数。

输出格式

输出一行一个整数,表示答案。

输入输出样例

输入

6 233 42
1 4 2 8 5 7

输出

91

说明/提示

对于 30 分的数据:
1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105
对于全部数据:
1 ≤ n ≤ 5 × 1 0 6 1≤n≤5×10^6 1n5×106

2 ≤ k < p ≤ 1 0 9 2≤k<p≤10^9 2k<p109
1 ≤ a i < p 1\le a_i < p 1ai<p
保证p为质数。

请注意常数优化 \color{red}\text{请注意常数优化} 请注意常数优化

思路

主流的做法是什么前缀积、后缀积,还有一堆常数优化。
但在一篇题解上看到更简单的方法:
首先边读入边通分,
我们由费马小定理: a p − 1 ≡ 1 ( m o d   p ) a^{p-1}≡1 (mod\ p) ap11(mod p),结合乘法逆元: a x ≡ 1 ( m o d   p ) ax≡1 (mod\ p) ax1(mod p)
可得: x = a p − 2 x=a^{p-2} x=ap2,再用快速幂求出即可

代码

#include<iostream>
#include<cstdlib>
#define ll unsigned long long
using namespace std;
ll n,p,k,kt,a,at,b=1;
ll read()
{
	char ch=getchar();
	ll x=0;
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+ch-48;
		ch=getchar(); 
	}
	return x;
}
ll fpow(ll a,ll b) //快速幂
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=(ans*a)%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}
int main()   
{	
	n=read();
	p=read();
	k=read();
	kt=k%p; 
	for(ll i=1;i<=n;i++)
	{
		at=read();
		a=(b*kt%p+a*at%p)%p;
		b=b*at%p;
		kt=kt*k%p;
	}
	printf("%lld",a*fpow(b,p-2)%p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值