原题链接
题目大意
给定
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。
对于
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<p\le 10^9,1\le a_i\le p
1≤n≤5×106,2≤k<p≤109,1≤ai≤p,保证
p
p
p 为质数。
解题思路
⚠
警告
此题时间限制仅有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<bits/stdc++.h>
#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 ∼