1. 程式人生 > 實用技巧 >乘法逆元2題解

乘法逆元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);
}