乘法逆元2题解

这是一篇题解类似物
提交记录记录了我的非酋历程
乘法逆元× 凭脸过题√
传送
我们首先看到这个东西

妙哇
对每个数都求一次逆元肯定是会被卡的,我们来看看要输出的东西有什么优雅的性质
我们不妨先暴力通分一下
原式=

\[ \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\n",fz);
}

posted @ 2020-06-28 21:41  千载煜  阅读(168)  评论(0编辑  收藏  举报