本文共 1256 字,大约阅读时间需要 4 分钟。
给定 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=1∑naiki 当然要对 p 取模。第一行三个正整数 n,p,k 意义如题目描述。
第二行 n 个正整数 a_i ,是你要求逆元的数。输出一行一个整数,表示答案。
6 233 421 4 2 8 5 7
91
对于 30 分的数据:
1 ≤ n ≤ 1 0 5 1≤n≤10^5 1≤n≤105 对于全部数据: 1 ≤ n ≤ 5 × 1 0 6 1≤n≤5×10^6 1≤n≤5×1062 ≤ k < p ≤ 1 0 9 2≤k<p≤10^9 2≤k<p≤109
1 ≤ a i < p 1\le a_i < p 1≤ai<p 保证p为质数。请注意常数优化 \color{red}\text{请注意常数优化} 请注意常数优化
主流的做法是什么前缀积、后缀积,还有一堆常数优化。
但在一篇上看到更简单的方法: 首先边读入边通分, 我们由费马小定理: a p − 1 ≡ 1 ( m o d p ) a^{p-1}≡1 (mod\ p) ap−1≡1(mod p),结合乘法逆元: a x ≡ 1 ( m o d p ) ax≡1 (mod\ p) ax≡1(mod p), 可得: x = a p − 2 x=a^{p-2} x=ap−2,再用快速幂求出即可#include#include #define ll unsigned long longusing 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);}
转载地址:http://thpwb.baihongyu.com/