题解 CF1109E【Sasha and a Very Easy Test】

$\text{Link}$

题意

给你一个长为 $n$ 的序列 $a$ 和一个数 $p$,有 $q$ 次操作,操作有 $3$ 种,分别是:

  1. 1 l r x,对 $\forall i\in[l,r],a_i\gets a_i\times x$;
  2. 2 c x,令 $a_c\gets \dfrac{a_c}{x}$,保证 $x\mid a_c$;
  3. 3 l r,查询 $\displaystyle\left(\sum_{i=l}^ra_i\right) \bmod p$。

时限 2.5s,$1\le n,q\le 10^5$,$1\le a_i,x\le 10^5$,$2\le p\le 10^9+9$。

思路

看到这个除法操作是非常难直接维护的,模数 $p$ 也不是质数,所以可以向维护质因子次数的方面想。

质数有很多,不可能每一个都直接维护,考虑维护质数的原因是 $p$ 不保证是质数,$x$ 不一定有逆元。而 $x$ 在模 $p$ 意义下有逆元当且仅当 $\gcd(x,p)=1$。考虑将 $x,p$ 分别分解质因数,$x$ 中不是 $p$ 的因数的质因数可以直接用 $x^{φ(p)-1}$ 计算逆元,只有 $p$ 的质因子需要特殊维护。

可以发现,由于 $p\le 10^9+9$,$p$ 的不同因数最多只有 $k=9$ 个,可以直接维护。使用线段树,标记存下这些信息即可。

时间复杂度 $O(kn\log n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=5e5+10;
int n,q,p,phi,cnt,sp[15];
inline int qpow(int x,int y){
    int res=1;
    while(y){
        if(y&1) res=1ll*res*x%p;
        x=1ll*x*x%p;
        y>>=1; 
    }
    return res;
}
struct node{
    int ep,op[15];
    inline void init(int x){
        for(int i=1;i<=cnt;i++){
            op[i]=0;
            while(x%sp[i]==0)
                op[i]++,x/=sp[i];
        }
        ep=x;
    }
    inline int getv(){
        int res=ep;
        for(int i=1;i<=cnt;i++)
            res=1ll*res*qpow(sp[i],op[i])%p;
        return res;
    }
    inline void set(){
        ep=1;
        memset(op,0,sizeof(op));
    }
    inline friend node operator*(const node &a,const node &b){
        node c;
        c.ep=1ll*a.ep*b.ep%p;
        for(int i=1;i<=cnt;i++)
            c.op[i]=a.op[i]+b.op[i];
        return c; 
    }
}s[N];
struct Segment_Tree{
    struct Node{
        int sum,tagm;
        node tagd;
    }a[N<<2];
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    inline void pushdown(int rt){
        a[ls].sum=1ll*a[ls].sum*a[rt].tagm%p;
        a[rs].sum=1ll*a[rs].sum*a[rt].tagm%p;
        a[ls].tagm=1ll*a[ls].tagm*a[rt].tagm%p;
        a[rs].tagm=1ll*a[rs].tagm*a[rt].tagm%p;
        a[ls].tagd=a[ls].tagd*a[rt].tagd;
        a[rs].tagd=a[rs].tagd*a[rt].tagd;
        a[rt].tagm=1,a[rt].tagd.set();
    }
    inline void pushup(int rt){
        a[rt].sum=(a[ls].sum+a[rs].sum)%p;
    }
    inline void build(int rt,int l,int r){
        a[rt].tagm=1,a[rt].tagd.set();
        if(l==r){
            a[rt].sum=s[l].getv();
            return ;
        }
        int mid=l+r>>1;
        build(ls,l,mid),build(rs,mid+1,r);
        pushup(rt);
    }
    inline void multi(int rt,int l,int r,int L,int R,node v){
        if(L<=l&&r<=R){
            a[rt].sum=1ll*a[rt].sum*v.getv()%p;
            a[rt].tagm=1ll*a[rt].tagm*v.getv()%p;
            a[rt].tagd=a[rt].tagd*v;
            return ;
        }
        pushdown(rt);
        int mid=l+r>>1;
        if(L<=mid) multi(ls,l,mid,L,R,v);
        if(R>mid) multi(rs,mid+1,r,L,R,v);
        pushup(rt);
    }
    inline void dived(int rt,int l,int r,int p,int v){
        if(l==r){
            s[p]=s[p]*a[rt].tagd;
            a[rt].tagd.set();
            for(int i=1;i<=cnt;i++)
                while(v%sp[i]==0)
                    s[p].op[i]--,v/=sp[i];
            s[p].ep=1ll*s[p].ep*qpow(v,phi-1)%(::p);
            a[rt].sum=s[p].getv();
            return ;
        }
        pushdown(rt);
        int mid=l+r>>1;
        if(p<=mid) dived(ls,l,mid,p,v);
        else dived(rs,mid+1,r,p,v);
        pushup(rt);
    }
    inline int query(int rt,int l,int r,int L,int R){
        if(L<=l&&r<=R) return a[rt].sum;
        pushdown(rt);
        int mid=l+r>>1,res=0;
        if(L<=mid) res=(res+query(ls,l,mid,L,R))%p;
        if(R>mid) res=(res+query(rs,mid+1,r,L,R))%p;
        return res;
    }
}T;
int main(){
    n=read(),p=read();
    int tmp;tmp=phi=p;
    for(int i=2;i*i<=p;i++){
        if(tmp%i==0){
            sp[++cnt]=i;
            phi=phi/i*(i-1);
            while(tmp%i==0) tmp/=i;
        }
    }
    if(tmp!=1){
        sp[++cnt]=tmp;
        phi=phi/tmp*(tmp-1);
    }
    for(int i=1;i<=n;i++)
        s[i].init(read());
    q=read();
    T.build(1,1,n);
    while(q--){
        int opt=read(),l=read(),r=read();
        if(opt==1){
            int x=read();
            node tmp;tmp.init(x);
            T.multi(1,1,n,l,r,tmp);
        }else if(opt==2){
            T.dived(1,1,n,l,r);
        }else{
            write(T.query(1,1,n,l,r)),putc('\n');
        }
    }
    flush();
}

再见 qwq~

posted @ 2022-07-29 14:41  ffffyc  阅读(14)  评论(0)    收藏  举报  来源