P5431
AC记录:Accepted
给定 n n n 个正整数 a i a_i ai,求它们在模 p p p 意义下的乘法逆元。
由于输出太多不好,所以将会给定常数 k k k,你要输出的答案为:
∑ i = 1 n k i a i \sum^n_{i=1}\frac{k^i}{a_i} i=1∑naiki
答案对 p p p 取模。
第一行三个正整数 n , p , k n,p,k n,p,k,意义如题目描述。
第二行 n n n 个正整数 a i a_i ai,是你要求逆元的数。
输出一行一个整数,表示答案。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input
6 233 42
1 4 2 8 5 7
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
91
H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain
自己手推吧。
对于 30 % 30\% 30%的数据, 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1≤n≤105。 1≤n≤5×106,2≤k<p≤109,1≤ai≤p
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 5 × 1 0 6 , 2 ≤ k < p ≤ 1 0 9 , 1 ≤ a i ≤ p 1≤n≤5\times 10^6,2\le k
⚠ 警告 此题时间限制仅有550ms! { \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 此题时间限制仅有550ms!}}} } ⚠ 警告此题时间限制仅有550ms!
出题人还算良心吧,就比乘法逆元 只多了50ms 。
顺便推销一下我写的乘法逆元的博客。
这次我们要用 阶乘求逆元 。
我们设 m u l i mul_i muli 为前 i i i 个数字的乘积, i n v m u l i invmul_i invmuli 为 m u l i mul_i muli 的逆元。
而题目里面的式子说是 ∑ i = 1 n k i a i \large\sum\limits^n_{i=1}\frac{k^i}{a_i} i=1∑naiki,是 k i k^i ki 和 1 a i \dfrac 1{a_i} ai1 也就是 a i a_i ai 的逆元的乘积。那么如何求单个元素 a i a_i ai 的乘积呢?
我们知道, i n v m u l i = 1 a 1 × a 2 × ⋯ × a i = 1 a 1 × a 2 × ⋯ × a i − 1 × 1 a i invmul_i=\dfrac 1{a_1\times a_2\times\cdots\times a_i}=\dfrac 1{a_1\times a_2\times\cdots\times a_{i-1}}\times\dfrac1{a_i} invmuli=a1×a2×⋯×ai1=a1×a2×⋯×ai−11×ai1,所以我们只要消掉 1 a 1 × a 2 × ⋯ × a i − 1 \dfrac 1{a_1\times a_2\times\cdots\times a_{i-1}} a1×a2×⋯×ai−11,即乘上 m u l i − 1 mul_{i-1} muli−1,就可以求出 a i a_i ai 的逆元。由此可得
1 a i = i n v m u l i × m u l i − 1 \frac1{a_i}=invmul_i\times mul_{i-1} ai1=invmuli×muli−1
然后就可以线性求逆元啦。
最后,还有一个优化,就是秦九韶算法,循环时,要 从大到小 循环,而每一次处理答案,只需要把答案乘 k k k 就可以了。
而 i n v m u l n invmul_n invmuln 可以由费马小定理求出,即 i n v m u l n = ( m u l n ) p − 2 invmul_n=(mul_n)^{p-2} invmuln=(muln)p−2。
#include
#define endl '\n'
using namespace std;
#define int long long
int mul[5000010];
int a[5000010];
int n,p,k;
int power(int a,int b,int p)
{
int tar=1;
while(b)
{
if(b&1)
tar=(long long)(tar*a)%p;
a=(long long)(a*a)%p;
b>>=1;
}
return tar;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
/* Code */
cin>>n>>p>>k;
mul[0]=1;
for(int i=1; i<=n; i++)
cin>>a[i],mul[i]=1ll*mul[i-1]*a[i]%p;
int invmul=power(mul[n],p-2,p);//算invmul[n]
int tar=0;
for(int i=n; i>=1; i--)
{
int invai=1ll*invmul*mul[i-1]%p;//求ai的逆元
tar=1ll*(tar+invai)*k%p;//秦九韶算法
invmul=(1ll*invmul*a[i])%p;//算invmul[i-1]
}
cout<<tar<<endl;
return 0;
}
完美切题 ∼ \sim ∼