其他分享
首页 > 其他分享> > CF1109E Sasha and a Very Easy Test 题解

CF1109E Sasha and a Very Easy Test 题解

作者:互联网

CF1109E in luogu

题意简述:

维护一个序列,给定三种操作:区间乘,单点除,区间求和。任意模数


思路:

操作就这么个操作,线段树套上就没了,重点在于任意模数的除法,不然这也不会是黑题了。

除数与模数不一定互质那就没法求逆元了。既然如此那就把数分为互质的部分和不互质的部分,不就解决了嘛?

具体的嗦,将模数分解质因数,一个数也可以拆分分为包含这些质因数的部分与不包含的部分,包含的那部分特殊处理,不包含的就互质了,可以用逆元。即:

\[mod=p_1^{c_1}×p_2^{c_2}×\cdots×p_{cnt}^{c_{cnt}} \]

\[x=a×p_1^{t_1}×p_2^{t_2}×\cdots×p_{cnt}^{t_{cnt}},\gcd(a,mod)=1 \]

其中\(mod\)每个质因子的次数没必要知道,而其他数是需要的。

在处理时,对于互质的部分\(a\),可以直接算,除法就用逆元(exgcd 或欧拉定理)。对于不互质的部分\(p\),就用次数相加减,在查询时再用快速幂算一遍。

关于线段树,由于除法是单点的,所以在线段树上我们没必要对每一处权值都这么处理,只处理单点即可。

具体的处理,pushup 与正常无异,但是 lazy 与 pushdown 需要特殊处理。并且对于每个单点的操作,可以直接用 lazy 储存,也只需要在做除法的时候,对于单点将 lazy 用掉,更新权值。所以为了提升效率,lazy 需要未经拆分的,应对区间乘操作,与拆分过的,应对单点除操作。


既然都要分解质因数了,那就顺便求个欧拉函数,用欧拉定理求逆元岂不美哉?关于欧拉函数与欧拉定理:

\[\varphi(n)=n×\prod_{i=1}^{cnt}\frac{p_i-1}{p_i} \]

\[a^{\varphi(p)}\equiv 1\quad mod\;p\;(\gcd(a,p)=1) \]

\[a^{\varphi(p)-1}\equiv a^{-1}\quad mod\;p\;(\gcd(a,p)=1) \]

顺便,对于逆元可以整个小记忆化...不过询问并没有那么多所以优化不大

代码 qwq:

#include<bits/stdc++.h>
#define ttT template <typename T>
#define EL puts("Elaina")
#define reg register int
#define qwq 0
using namespace std;
inline char gc(){
    static char buf[1<<21],*p1,*p2;
    if(p1==p2){p1=buf,p2=buf+fread(buf,1,1<<21,stdin);if(p1==p2)return EOF;}
    return *p1++;
}
ttT inline void read(T &x){
    x=0;int f=1;char ch=gc();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    x*=f;
}
typedef long long ll;
const int maxn=1e5+3;
int n,mod,phi,p[11],pcnt,invv[maxn];
inline int qpow(int a,int b){
    int ans=1;a%=mod;
    for(;b;b>>=1,a=1ll*a*a%mod)
        if(b&1)ans=1ll*ans*a%mod;
    return ans;
}
inline int inv(int x){
    return invv[x]?invv[x]:invv[x]=qpow(x,phi-1);
}
struct num{
    int x,np[11];
    num(){};
    num(int n){
        x=0,memset(np,0,sizeof(np));
        if(n==1){x=1;return;}
        for(reg i=1;i<=pcnt;++i)
            while(n%p[i]==0)np[i]++,n/=p[i];
        x=n;
    }
    inline int calc(){
        int ans=x;
        for(reg i=1;i<=pcnt;++i)ans=1ll*ans*qpow(p[i],np[i])%mod;
        return ans;
    }
};
#define lt (k<<1)
#define rt (k<<1|1)
num a[maxn];
struct node{
    int l,r,x,lzy;
    num lazy;
}t[maxn<<2];
inline void pushup(int k){
    t[k].x=(t[lt].x+t[rt].x)%mod;
}
inline void pushdown(int k){
    t[lt].x=1ll*t[lt].x*t[k].lzy%mod,t[rt].x=1ll*t[rt].x*t[k].lzy%mod;
    t[lt].lzy=1ll*t[lt].lzy*t[k].lzy%mod,t[rt].lzy=1ll*t[rt].lzy*t[k].lzy%mod;
    t[lt].lazy.x=1ll*t[lt].lazy.x*t[k].lazy.x%mod;
    t[rt].lazy.x=1ll*t[rt].lazy.x*t[k].lazy.x%mod;
    for(reg i=1;i<=pcnt;++i){
        t[lt].lazy.np[i]+=t[k].lazy.np[i];
        t[rt].lazy.np[i]+=t[k].lazy.np[i];
        t[k].lazy.np[i]=0;
    }
    t[k].lzy=t[k].lazy.x=1;
}
inline void build(int k,int l,int r){
    t[k].l=l,t[k].r=r,t[k].lzy=1,t[k].lazy=num(1);
    if(l==r)t[k].x=a[l].calc();
    else{
        int mid=(l+r)>>1;
        build(lt,l,mid);
        build(rt,mid+1,r);
        pushup(k);
    }
}
inline void updata(int k,int L,int R,int x,num xx){
    if(L<=t[k].l&&t[k].r<=R){
        t[k].x=1ll*t[k].x*x%mod;
        t[k].lzy=1ll*t[k].lzy*x%mod;
        t[k].lazy.x=1ll*t[k].lazy.x*xx.x%mod;
        for(reg i=1;i<=pcnt;++i)t[k].lazy.np[i]+=xx.np[i];
    }
    else{
        int mid=(t[k].l+t[k].r)>>1;
        pushdown(k);
        if(L<=mid)updata(lt,L,R,x,xx);
        if(R>mid)updata(rt,L,R,x,xx);
        pushup(k);
    }
}
inline void updata(int k,int pi,int x){
    if(t[k].l==t[k].r){
        a[pi].x=1ll*a[pi].x*t[k].lazy.x%mod,t[k].lazy.x=1;
        for(reg i=1;i<=pcnt;++i){
            a[pi].np[i]+=t[k].lazy.np[i];
            while(x%p[i]==0)a[pi].np[i]--,x/=p[i];
            t[k].lazy.np[i]=0;
        }
        a[pi].x=1ll*a[pi].x*inv(x)%mod;
        t[k].x=a[pi].calc();
    }
    else{
        int mid=(t[k].l+t[k].r)>>1;
        pushdown(k);
        if(pi<=mid)updata(lt,pi,x);
        else updata(rt,pi,x);
        pushup(k);
    }
}
inline int query(int k,int L,int R){
    if(L<=t[k].l&&t[k].r<=R)return t[k].x;
    else{
        int mid=(t[k].l+t[k].r)>>1,ans=0;
        pushdown(k);
        if(L<=mid)ans=(1ll*ans+query(lt,L,R))%mod;
        if(R>mid)ans=(1ll*ans+query(rt,L,R))%mod;
        return ans;
    }
}
void solve(){
    read(n),read(mod);
    int dom=phi=mod;
    for(reg i=2;i*i<=mod;++i)
        if(dom%i==0){
            p[++pcnt]=i;
            phi=phi/i*(i-1);
            while(dom%i==0)dom/=i;
        }
    if(dom^1)p[++pcnt]=dom,phi=phi/dom*(dom-1);
    for(reg i=1,x;i<=n;++i)
        read(x),a[i]=num(x);
    build(1,1,n);
    int q,opt,l,r,x;
    read(q);
    while(q--){
        read(opt);
        if(opt==1){
            read(l),read(r),read(x);
            updata(1,l,r,x,num(x));
        }
        else if(opt==2){
            read(l),read(x);
            updata(1,l,x);
        }
        else{
            read(l),read(r);
            printf("%d\n",query(1,l,r));
        }
    }
}
int main(){
    solve();
    return qwq;
}

标签:lazy,单点,Very,题解,CF1109E,int,ans,互质,mod
来源: https://www.cnblogs.com/muel-imj/p/16025443.html