[洛谷P5431][题解][模板]乘法逆元2

我是题目吗?

这道题乍一看非常简单,然而数据范围和时限直接劝退

其实还是很简单

考虑如何求a(i)逆元的和

这里需要用到一个前缀积s(i)

那么s(i)的逆元就是a(1)乘到a(i)的逆元

所以1/s(i-1)=1/s(i)*a(i)

1/a(i)=s(i-1)*1/s(i)

复杂度O(3n+logp)卡一卡可以过

Code:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define N 5000010
 4 using namespace std;
 5 int n,p,k,tmp,ans;
 6 int a[N],s[N],invs[N];
 7 /*--------卡常--------*/ 
 8 inline int rd(){
 9     int x=0;
10     char c=getchar();
11     while(c<'0'||c>'9')c=getchar();
12     while(c>='0'&&c<='9'){
13         x=x*10+c-'0';
14         c=getchar();
15     }
16     return x;
17 }
18 inline void prt(int x){
19     if(x>=10)prt(x/10);
20     putchar(x%10+'0');
21 }
22 /*--------卡常--------*/ 
23 inline int quickp(int a,int b){
24     int ans=1;
25     while(b){
26         if(b&1){
27             ans=(ans*a)%p;
28         }
29         a=(a*a)%p;
30         b>>=1;
31     }
32     return ans;
33 }
34 signed main(){
35     s[0]=1;
36     n=rd(),p=rd(),k=rd();
37     //第一遍求前缀积 
38     for(int i=1;i<=n;i++){
39         a[i]=rd();
40         s[i]=(s[i-1]*a[i])%p;
41     }
42     //预处理出来sn的逆元 
43     invs[n+1]=quickp(s[n],p-2);
44     //第二遍倒着求前缀积的逆元 
45     for(int i=n;i>=1;i--){
46         invs[i]=(invs[i+1]*a[i])%p;
47     }
48     tmp=k;
49     //第三遍乘出答案 
50     for(int i=1;i<=n;i++){
51         ans=(ans+((invs[i+1]*s[i-1])%p*tmp)%p)%p;
52         tmp=(tmp*k)%p;
53     }
54     prt(ans);
55     return 0;//Perfect~
56 }

P.S.时间限制550ms 提交记录最慢的点532ms

内容来自_ajhfff_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
原文地址:https://www.cnblogs.com/juruoajh/p/12150324.html