Codeforces 1114 F —— 线段树优化+欧拉函数的一些性质

This way

题意:

给你n个数,每次有两种操作:
TOTIENT l r 问你从x到y区间
在这里插入图片描述
MULTIPLY l r x 将l到r的区间的值乘上x

题解:

对于欧拉函数来说
1.如果x,y互质 φ ( x y ) = φ ( x ) φ ( y ) φ(x*y)=φ(x)*φ(y)
2.如果p是质数 φ ( x y ) = x y x y 1 φ(x^y)=x^y-x^{y-1}
那么乘上一个数我们可以用唯一分解定理将它分解变成1之后,再对每个质数用2去做。
但是很明显不能O(n)的去做,然后发现这个无所谓顺序并且可以合并,并且它还有区间更新区间查询,那么就考虑线段树优化。
并且我们知道第二个性质就是 ( x 1 ) x y 1 (x-1)x^{y-1} ,那么我们就只需要维护一下每种质数是否有,然后最后再乘个逆元什么的就行了。发现300之内的质数只有62个,于是用long long来存状态。于是线段树维护两个东西:当前区间有的值的状态,当前区间的答案。
时间复杂度极其差劲,用快读也要4700+,我估计是取模太多了,然后模乘也不知道怎么改才能在cf上用,有没有大佬知道取模优化方法的可以在下面留言
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pa pair<ll,ll>
const int N=4e5+5;
const ll mod=1e9+7;
ll p[N],np[N],cnt;
ll qpow(ll a,ll b){ll ans=1;for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;return ans;}
ll inv[65],inv1[65];
ll s[N*4],sum[N*4],f[N*4],fs[N*4],a[N];
void push_down(int l,int r,int root){
    int mid=l+r>>1;
    f[root<<1]=f[root<<1]*f[root]%mod;
    fs[root<<1]|=fs[root];
    f[root<<1|1]=f[root<<1|1]*f[root]%mod;
    fs[root<<1|1]|=fs[root];
    sum[root<<1]=sum[root<<1]*qpow(f[root],mid-l+1)%mod;
    s[root<<1]|=fs[root];
    sum[root<<1|1]=sum[root<<1|1]*qpow(f[root],r-mid)%mod;
    s[root<<1|1]|=fs[root];
    fs[root]=0;
    f[root]=1;
}
void update(int l,int r,int root,int ql,int qr,ll v,ll msk){
    if(l>=ql&&r<=qr){
        f[root]=f[root]*v%mod;
        fs[root]|=msk;
        sum[root]=sum[root]*qpow(v,r-l+1)%mod;
        s[root]|=msk;
        return ;
    }
    int mid=l+r>>1;
    push_down(l,r,root);
    if(mid>=ql)
        update(l,mid,root<<1,ql,qr,v,msk);
    if(mid<qr)
        update(mid+1,r,root<<1|1,ql,qr,v,msk);
    s[root]=s[root<<1]|s[root<<1|1];
    sum[root]=sum[root<<1]*sum[root<<1|1]%mod;
}
pa query(int l,int r,int root,int ql,int qr){
    if(l>=ql&&r<=qr)
        return {sum[root],s[root]};
    int mid=l+r>>1;
    push_down(l,r,root);
    pa ans={1,0};
    if(mid>=ql)
        ans=query(l,mid,root<<1,ql,qr);
    if(mid<qr){
        pa ne=query(mid+1,r,root<<1|1,ql,qr);
        ans.first=ans.first*ne.first%mod;
        ans.second|=ne.second;
    }
    return ans;
}
char ss[25];
int main()
{
    for(int i=2;i<=300;i++){
        if(!np[i]){
            p[cnt++]=i;
            inv[cnt-1]=qpow(p[cnt-1],mod-2);
            inv1[cnt-1]=qpow(p[cnt-1]-1,mod-2);
            for(int j=i*i;j<=300;j+=i)
                np[j]=1;
        }
    }
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n*4;i++)
        sum[i]=f[i]=1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]==1)
            continue;
        ll msk=0;
        for(int j=0;j<cnt;j++)
            if(a[i]%p[j]==0)
                msk|=(1ll<<j);
        update(1,n,1,i,i,a[i],msk);
    }
    int l,r,v;
    while(q--){
        scanf("%s%d%d",ss,&l,&r);
        if(ss[0]=='T'){
            pa ans=query(1,n,1,l,r);
            for(int i=0;i<cnt;i++)
                if(ans.second&(1ll<<i))
                    ans.first=ans.first*(p[i]-1)%mod*inv[i]%mod;
            printf("%lld\n",ans.first);
        }
        else{
            scanf("%d",&v);
            if(v==1)continue;
            ll msk=0;
            for(int j=0;j<cnt;j++)
                if(v%p[j]==0)
                    msk|=(1ll<<j);
            update(1,n,1,l,r,v,msk);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/107346323