【模板】模意义下的乘法逆元 2(快读+数学)

108 篇文章 0 订阅
31 篇文章 0 订阅

【模板】模意义下的乘法逆元 2

题目描述

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

由于输出太多不好,所以将会给定常数 k k k,你要输出的答案为:
∑ i = 1 n k i a i \sum\limits_{i=1}^n\frac{k^i}{a_i} i=1naiki

答案对 p p p 取模。

输入格式

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

输出格式

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

样例 #1

样例输入 #1

6 233 42
1 4 2 8 5 7

样例输出 #1

91

提示

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 1 0 5 1\le n \le 10^5 1n105

对于 100 % 100\% 100% 数据, 1 ≤ n ≤ 5 × 1 0 6 1\le n \le 5\times 10^6 1n5×106 2 ≤ k < p ≤ 1 0 9 2\le k < p \le 10^9 2k<p109 1 ≤ a i < p 1\le a_i < p 1ai<p,保证 p p p 为质数。

提示:本题时间限制较为严格,请注意使用较快的 IO 方式。

思路

根据题目,我们要求的是:

∑ i = 1 n k i a i = ∑ i = 1 n k i ⋅ w i − 1 \sum_{i=1}^{n}{\frac{k^i}{a_i}}=\sum_{i=1}^{n}{k^i\cdot w_i^{-1}} i=1naiki=i=1nkiwi1
我们考虑先求出 w w w 序列的前缀积,记为 s s s
s i = ∏ j = 1 i w j s_i=\prod_{j=1}^{i}{w_j} si=j=1iwj
w w w 序列前缀积的逆元为 t t t ,此时如果我们知道这个序列,我们就可以知道 w w w 中任意一个数的逆元:
w i − 1 = s i − 1 × t i w_i^{-1}=s_{i-1}\times t_i wi1=si1×ti
我们还知道:前缀积的逆元就等于逆元的前缀积 ,所以我们只要求出 t n t_n tn 就可以线性递推出整个 t t t 序列了:
t n = s n p − 2 t_n=s_n^{p-2} tn=snp2
t i = w i + 1 × t i + 1 t_i=w_{i+1}\times t_{i+1} ti=wi+1×ti+1
这样我们就求得了 w w w 序列的逆元,然后再累加一下再乘 k k k 就是我们的答案了。

代码

#include<cstdio>

#define int long long

using namespace std;

const int N = 5e6+10;

int w[N];
int s[N],ins[N];//ins逆元前缀和
int n,p,k;
int ans;

int read(){
    int x=0;
    char ch=getchar();
    
    while(!(ch>='0'&&ch<='9')){
        ch=getchar();
    }
    
    while(ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    
    return x;
}

int qmi(int a,int b,int p){
    int res=1;
    
    while(b){
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}

signed main(){
    
    n=read(),p=read(),k=read();
    
    s[0]=1;
    for(int i=1;i<=n;i++){
        w[i]=read();
        s[i]=s[i-1]*w[i]%p;
    }
    
    ins[n]=qmi(s[n],p-2,p);
    
    for(int i=n-1;i;i--){
        ins[i]=ins[i+1]*w[i+1]%p;
    }
    for(int i=n;i;i--){
        ans=(ans+ins[i]*s[i-1]%p)*k%p;
    }
    
    printf("%lld",ans);
    
    return 0;
    
}
  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值