洛谷 P5431 【模板】乘法逆元2(卡常)

传送门


解题思路

(O(n)) 内求出 (n) 个数的逆元:
(S=sum_{i=1}^{n}a[i])
(a[i]^{-1}=frac{S/a[i]}{S}=S_1[i-1]*S_2[n-i]*S^{-1})
其中 (S_1)(a[i]) 的前缀积,(S_2)(a[i]) 的后缀积。
(O(n)) 预处理,(O(1)) 求。
因为这次要卡常,所以用了题解的快读(真的强大)

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=5e6+5;
int n,p,k,k0,s1[maxn],s2[maxn],a[maxn];
long long ans;
template <typename T>
inline void read(T &x)//快读
{
    char c;
    x=0;
    int fu=1;
    c=getchar();
    while(c>57||c<48){
        if(c==45){
        	fu=-1;
        }
        c=getchar();
    }
    while(c<=57&&c>=48)
    {
        x=(x<<3)+(x<<1)+c-48;
        c=getchar();
    }
    x*=fu;
}
int ksm(int a,int b){
	if(b==1) return a%p;
	long long res=ksm(a,b/2);
	if(b&1) return (long long)res*res%p*a%p;
	return	(long long)res*res%p;
}
int main(){
	read(n);
	read(p);
	read(k0);
	k=k0;
	s1[0]=s2[0]=1;
	for(int i=1;i<=n;i++){
		read(a[i]);
		s1[i]=(long long)s1[i-1]*a[i]%p;
	}
	for(int i=1;i<=n;i++){
		s2[i]=(long long)s2[i-1]*a[n-i+1]%p;
	}
	for(int i=1;i<=n;i++){
		ans+=(long long)k*s1[i-1]%p*s2[n-i]%p;
		k=(long long)k*k0%p;
	}
	printf("%lld",ans%p*ksm(s1[n],p-2)%p);
    return 0;
}
原文地址:https://www.cnblogs.com/yinyuqin/p/14906382.html