这是一篇题解类似物
提交记录记录了我的非酋历程
乘法逆元× 凭脸过题√
传送
我们首先看到这个东西
妙哇
对每个数都求一次逆元肯定是会被卡的,我们来看看要输出的东西有什么优雅的性质
我们不妨先暴力通分一下
原式=
[ frac{1}{a_1a_2.....a_n} sum_{i=1}^{n}frac{k^ia_1a_2...a_n}{a_i}
]
设(a_1a_2...a_n=M),则原式=
[ frac{1}{M} sum_{i=1}^n frac{k^iM}{a_i}
]
考虑到(frac{M}{a_i})还要求逆元,所以我们求前缀积和后缀积。用前缀积和后缀积来表示(frac{M}{a_i})即可。
最后只用对(M)求逆元。因为这里保证(p)是质数,所以费马小定理适用
然鹅这题卡常,所以我们需要用毒瘤卡常技巧以及脸来过掉这道题
一些技巧
1.少开(int)
2.用(inline)
3.实测(+p)%p比%p要快
4.讨好评测姬实测有用
5.让你的号变白一点
还是想抱怨一句小号卡了2遍过同样的代码大号又卡了37次才过难道这就是新号buff吗i了i了
代码如下(过不了就去试试讨好评测姬叭)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define pa pair<int,int>
using namespace std;
typedef long long ll;
const double eps=1e-13;
inline int read(){
char ch=getchar();
int x=0;bool f=0;
while(ch<'0'||ch>'9')
{
if(ch=='-') f=1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return f?-x:x;
}
int n,p,k,a[5000009],M;
ll ji[2][5000009],kk=1,fz;//1 qz,0 hz
int ksm(ll a,int b){
ll rtn=1;
while(b){
if(b&1) rtn=(rtn*a)%p;
a=(a*a)%p;
b>>=1;
}
return rtn;
}
int main(){
n=read();p=read();k=read();ji[1][0]=1;ji[0][n+1]=1;
for(register int i=1;i<=n;++i) a[i]=read(),ji[1][i]=(ji[1][i-1]*a[i]+p)%p;//inv[i]==inv[i%p]???
for(register int i=n;i>=1;--i) ji[0][i]=(ji[0][i+1]*a[i]+p)%p;
for(register int i=1;i<=n;++i){
kk=(kk*k+p)%p;
fz=(fz+kk*ji[1][i-1]%p*ji[0][i+1]+p)%p;
}
M=(ksm(ji[1][n],p-2));
fz=(fz*M+p)%p;
printf("%d
",fz);
}