其他分享
首页 > 其他分享> > P5431 【模板】乘法逆元 2

P5431 【模板】乘法逆元 2

作者:互联网

Problem:

题目描述

给定 \(n\) 个正整数 \(a_i\) ,求它们在模 \(p\) 意义下的乘法逆元。

由于输出太多不好,所以将会给定常数 \(k\),你要输出的答案为:

\[\sum\limits_{i=1}^n\frac{k^i}{a_i} \]

答案对 \(p\) 取模。

输入格式

第一行三个正整数 \(n,p,k\),意义如题目描述。
第二行 \(n\) 个正整数 \(a_i\),是你要求逆元的数。

输出格式

输出一行一个整数,表示答案。

样例 #1

样例输入 #1

6 233 42
1 4 2 8 5 7

样例输出 #1

91

提示

对于 \(30\%\) 的数据,\(1\le n \le 10^5\)。

对于 \(100\%\) 数据,\(1\le n \le 5\times 10^6\),\(2\le k < p \le 10^9\),\(1\le a_i < p\),保证 \(p\) 为质数。

Solution

注意到此题的 \(n\) 高达 5e6,因此我们无法求 O(n) 次逆元。

因此考虑通分,因为通分后就只剩一个大分数了,那么只用求分母的一次逆元即可。

很显然通分后是 \(\dfrac{\sum\limits_{i}k^i\prod\limits_{j\ne i}a_j}{\prod a_i}\)。

下面分母求一次逆元即可,上面分子的话我们不难发现 \(\prod\limits_{j\ne i}a_j=(\prod\limits_{j<i}a_j)(\prod\limits_{j>i}a_j)\),直接预处理前后缀积,然后 \(k^i\) 递推维护即可。

时间复杂度 O(n)。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
#define timeused() (double)clock()/CLOCKS_PER_SEC
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define repp(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
template<typename T> inline T rd(T& x){
    T f=1;x=0;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(T)(c-'0');
    x*=f;
    return x;
}
ll n,p,k,a[6000005],pre[6000005],suf[6000005],ans;
ll qp(ll b,ll P,ll mod){
    ll ans=1,base=b;
    while(P){
        if(P&1) ans=ans*base%mod;
        base=base*base%mod;
        P>>=1;
    }
    return ans;
}
int main(){
    rd(n);
    rd(p);
    rd(k);
    rep(i,1,n) rd(a[i]);
    pre[0]=1;
    suf[n+1]=1;
    rep(i,1,n) pre[i]=pre[i-1]*a[i]%p;
    repp(i,n,1) suf[i]=suf[i+1]*a[i]%p;
    ll base=1;
    rep(i,1,n){
        base=base*k%p;
        ans+=pre[i-1]*suf[i+1]%p*base%p;
        ans%=p;
    }
    printf("%lld",ans*qp(pre[n],p-2,p)%p);
}

标签:pre,le,limits,rd,P5431,逆元,模板,define
来源: https://www.cnblogs.com/Miracle-blog/p/16299445.html