https://ac.nowcoder.com/acm/contest/19483/A
一个前缀积的问题,但是由于自己一开始不会逆元(数论0基础QAQ)自然在取模时出了错
于是先用线段树冲了一发
线段树:
#include <bits/stdc++.h> using namespace std; const int N = 1e5+5,mod = 1e9+7; int m,p; int a[N]; struct Node{ int l,r; long v; }tr[N*4]; void pushup(int u){ tr[u].v=(tr[u<<1].v*tr[u<<1|1].v)%mod; } void build(int u,int l, int r){ tr[u]={l,r}; if(l==r) { tr[u]={l,r,a[r]}; return; } int mid=l+r>>1; build(u<<1,l,mid),build(u<<1|1,mid+1,r); pushup(u); } int query(int u,int l,int r){ if(tr[u].l>=l &&tr[u].r<=r) return tr[u].v; int mid = tr[u].l + tr[u].r>>1; long v=1; if(l<=mid) v=query(u<<1,l,r); if(r>mid) v=(v*query(u<<1|1,l,r))%mod; return v; } int main(){ int n=0,last=0; scanf("%d %d",&m,&p); for(int i=1;i<=m;i++){ cin>>a[i]; } build(1,1,m); int x,y; while(p--){ scanf("%d %d",&x,&y); printf("%d\n",query(1,x,y)%mod); } return 0; }
听了zngg的直播课之后理解了逆元,来简单解释一下:
逆元为什么会出现?
我们在取模时,可以发现,加减乘法,在取模之后在进行运算是不影响运算结果的
但是除法就会影响
数学家们显然是无法容忍这种局面,于是创造了“逆元”
我们在进行取模运算时,一个数n对应的模数有一个大小为n,从0开始的集合,称为其的
“完全剩余系”(如5的完全剩余系为0~4)
不在完全剩余系的数都能对应到一个完全剩余系的数
整数是,小数一样是,逆元运算就是将除数转化为其在完全剩余系中对应的数
使得除法的结果也符合取模运算的规则
具体的求证过程可以去参考专门的博客哒,我就不细写了!下面放代码
前缀积+乘法逆元
#include<bits/stdc++.h> using namespace std; const int N = 300005; const long long mod = 1e9 + 7; #define LL long long LL quickpow(LL x, LL y, LL MOD){//快速幂,求逆元时使用 LL bs = 1; while (y){ if (y & 1) bs = (x * bs) % MOD; x = (x * x) % MOD; y >>= 1; } return bs; } LL get_inv(LL x){ return quickpow(x, mod - 2, mod);//费马小定理求逆元 } int n, l, r, m; LL a[N], pre[N]; int main(){ scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i){ scanf("%lld", &a[i]); } pre[0] = 1; for (int i = 1; i <= n; ++i){ pre[i] = pre[i - 1] * a[i] % mod; } while (m--){ scanf("%d %d", &l, &r); printf("%lld\n", pre[r]*get_inv(pre[l - 1]) % mod); //用逆元代替除数然后取模,非常自然的得到结果 } return 0; }