简单说下题意,给你一个长度为
数列
,
,
,让你求
这道题很明显是一个乘法逆元的题,因为我们要对分母取模
首先我们很容易想到的是给每个
都求一下逆元,复杂度是
但是很明显是过不了的,因为数据范围写着呢
很明显是过不去的,所以求
次逆元肯定是不可能的,我们看看能不能让求逆元的次数尽量的少
我们往傻了想
小学几年级忘了,学了个东西叫做通分对不对,我们把上面那个玩意通分一下,变成我们要求这个东西:
还是不好求,继续化简
加起来
然后就很明显了,我们可以先求分子,分母只需要最后求一次逆元就可以出来了,不懂的可以去看看我之前的博客广告 广告
这里因为保证
是质数,直接费马小定理就可以(第一个广告)
对于分子怎么做,我们可以预处理前缀积和后缀积
和
那么答案就是
这样就可以 求了
这道题很仁慈的地方是不用龟速乘
代码:
# 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基础语法…