乘法逆元进阶([模板]乘法逆元 2)

题目链接

简单说下题意,给你一个长度为 n n 数列 a a k k p p ,让你求
i = 1 n k i a i m o d   p \sum_{i=1}^n {\frac{k^i}{a_i}} mod \ p
这道题很明显是一个乘法逆元的题,因为我们要对分母取模

首先我们很容易想到的是给每个 a i a_i 都求一下逆元,复杂度是 O ( n l o g p ) O(nlogp)
但是很明显是过不了的,因为数据范围写着呢
n 5 × 1 0 6 , p 1 0 9 n\leq 5\times10^6,p\leq 10^9
很明显是过不去的,所以求 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 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 ( 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
然后就很明显了,我们可以先求分子,分母只需要最后求一次逆元就可以出来了,不懂的可以去看看我之前的博客广告 广告
这里因为保证 p p 是质数,直接费马小定理就可以(第一个广告)
对于分子怎么做,我们可以预处理前缀积和后缀积 m u l f i mulf_i m u l b i mulb_i
那么答案就是
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

这样就可以 O ( n ) O(n) 求了

这道题很仁慈的地方是不用龟速乘 e m m m 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基础语法…

发布了45 篇原创文章 · 获赞 52 · 访问量 9646

猜你喜欢

转载自blog.csdn.net/devout_/article/details/104182240