简单说下题意,给你一个长度为
n
n
n数列
a
a
a,
k
k
k,
p
p
p,让你求
∑
i
=
1
n
k
i
a
i
m
o
d
p
\sum_{i=1}^n {\frac{k^i}{a_i}} mod \ p
i=1∑naikimod p
这道题很明显是一个乘法逆元的题,因为我们要对分母取模
首先我们很容易想到的是给每个
a
i
a_i
ai都求一下逆元,复杂度是
O
(
n
l
o
g
p
)
O(nlogp)
O(nlogp)
但是很明显是过不了的,因为数据范围写着呢
n
≤
5
×
1
0
6
,
p
≤
1
0
9
n\leq 5\times10^6,p\leq 10^9
n≤5×106,p≤109
很明显是过不去的,所以求
n
n
n次逆元肯定是不可能的,我们看看能不能让求逆元的次数尽量的少
我们往傻了想
小学几年级忘了,学了个东西叫做通分对不对,我们把上面那个玩意通分一下,变成我们要求这个东西:
∑
i
=
1
n
k
i
⋅
∏
j
=
1
n
a
j
a
i
⋅
∏
j
=
1
n
a
j
m
o
d
p
\sum_{i=1}^n {\frac{k^i \cdot \prod_{j=1}^n a_j}{a_i\cdot \prod_{j=1}^n a_j} }mod \ p
i=1∑nai⋅∏j=1najki⋅∏j=1najmod p
还是不好求,继续化简
∑
i
=
1
n
k
i
⋅
∏
j
=
1
i
−
1
a
j
⋅
∏
j
=
i
+
1
n
a
j
∏
j
=
1
n
a
j
m
o
d
p
\sum_{i=1}^n{\frac{k^i\cdot \prod_{j=1}^{i-1} a_j\cdot \prod_{j=i+1}^n a_j}{\prod _{j=1}^n a_j}}mod \ p
i=1∑n∏j=1najki⋅∏j=1i−1aj⋅∏j=i+1najmod p
加起来
∑
i
=
1
n
(
k
i
⋅
∏
j
=
1
i
−
1
a
j
⋅
∏
j
=
i
+
1
n
a
j
)
∏
j
=
1
n
a
j
m
o
d
p
\frac{\sum_{i=1}^n (k^i\cdot \prod_{j=1}^{i-1} a_j\cdot \prod_{j=i+1}^n a_j)}{\prod _{j=1}^n a_j}mod \ p
∏j=1naj∑i=1n(ki⋅∏j=1i−1aj⋅∏j=i+1naj)mod p
然后就很明显了,我们可以先求分子,分母只需要最后求一次逆元就可以出来了,不懂的可以去看看我之前的博客广告 广告
这里因为保证
p
p
p是质数,直接费马小定理就可以(第一个广告)
对于分子怎么做,我们可以预处理前缀积和后缀积
m
u
l
f
i
mulf_i
mulfi和
m
u
l
b
i
mulb_i
mulbi
那么答案就是
∑
i
=
1
n
(
k
i
⋅
m
u
l
f
i
−
1
⋅
m
u
l
b
i
+
1
)
×
(
∏
i
=
1
n
a
i
)
−
1
m
o
d
p
\sum_{i=1}^n(k^i\cdot mulf_{i-1}\cdot mulb_{i+1})\times (\prod_{i=1}^n a_i)^{-1} mod \ p
i=1∑n(ki⋅mulfi−1⋅mulbi+1)×(i=1∏nai)−1mod p
这样就可以 O ( n ) O(n) O(n)求了
这道题很仁慈的地方是不用龟速乘 e m m m emmm emmm
代码:
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=5e6+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int long long
int n,p,k,ans,mult;
int a[N];
int mulf[N],mulb[N];
int Qpow(int base,int ind){
int res=1;
while(ind){
if(ind&1)res=res*base%p;
base=base*base%p;
ind>>=1;
}
return res;
}
signed main()
{
read(n),read(p),read(k);
Rep(i,1,n)read(a[i]);
mulf[0]=mulb[n+1]=1;
Rep(i,1,n)mulf[i]=(mulf[i-1]*a[i])%p;
_Rep(i,n,1)mulb[i]=(mulb[i+1]*a[i])%p;
mult=1;
Rep(i,1,n){
mult=mult*k%p;
ans=(ans+mult*mulf[i-1]%p*mulb[i+1])%p;
}
printf("%lld\n",ans*Qpow(mulf[n],p-2)%p);
return 0;
}
这道题的一大收获就是巩固了Markdown基础语法…