zoukankan      html  css  js  c++  java
  • CodeForces 1114F--Please, another Queries on Array?(欧拉函数+线段树)

    题目链接:https://codeforces.com/problemset/problem/1114/F

    题目大意:给你n个数,q次操作,类型1,将区间[l,r]中每个数乘以x,类型2,询问$varphi (prod_{i=l}^{r}a_i)$。其中初始的n个数每个小于等于300,x<=300。

    Example

    Input
    4 4
    5 9 1 2
    TOTIENT 3 3
    TOTIENT 3 4
    MULTIPLY 4 4 3
    TOTIENT 4 4
    Output
    1
    1
    2

    emmmm,线段树肯定要用上,接下来就是对于欧拉函数的性质的运用了,对于欧拉函数$varphi (x)$来讲,如果$x$可以表示为两个互质的数的乘积即$x=a imes b$,那么$varphi (x)=varphi (a) imes varphi (b)$。如果$x$可以表示为一个质数的幂的形式即$x=p^k$,$p$为质数。那么$varphi (p^k)=p^k-p^{k-1}=(1-p)p^{k-1}$。

    那么也就是说我们可以将每个数进行质因子分解,那么则有

    $sum=varphi (p_1^{k_1} imes p_2^{k2} imes p_3^{k_3}...)=varphi(p_1^{k_1-1}) imes varphi(p_2^{k_2-1}) imes...$

    $sum=(p_1-1)p_1^{k_1-1} imes (p_2-1)p_2^{k_2-1} imes (p_3-1)p_3^{k_3-1}...$

    那么也就是我们只需要维护一下$p_i-1$和$p_i^{k_i-1}$就可以了,按照我自己的超级复杂的写法就是先把每个数分解了,然后在300内筛选素数,总共62个,然后用状压来表示这些数是否存在,区间融合的时候需要对左儿子和右儿子的状态进行判断,是否存在出现了相同的素数,如果出现了,我们就对维护的$p_i^{k_i-1}$里面再乘上该素数。总的来说有点复杂,时间上是$O(62qlogn)$。。。直接T13了。。。。以下是刚开始的复杂写法:

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    #define lc rt<<1
    #define rc rt<<1|1
    typedef long long ll;
    const int mac=4e5+10;
    const ll mod=1e9+7;
    
    int a[mac],vis[350],prime[100],cnt=0;
    ll yes_stk=0;
    struct node
    {
        int l,r;
        ll stk,mul;//mul为剩余的p^k-1的乘积
        ll fstk,fmul,orig;
    }tree[mac<<2];
    
    ll qpow(ll a,ll b)
    {
        ll ans=1;
        a%=mod;
        while (b){
            if (b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans%mod;
    }
    
    void push_up(int rt)
    {
        tree[rt].mul=tree[lc].mul*tree[rc].mul%mod;
        for (int i=0; i<cnt; i++)
            if ((tree[lc].stk&(1LL<<i)) && (tree[rc].stk&(1LL<<i)))
                tree[rt].mul=tree[rt].mul*prime[i]%mod;
        tree[rt].stk=tree[lc].stk|tree[rc].stk;
    }
    
    void push_down(int rt)
    {
        for (int i=0; i<cnt; i++){
            if ((tree[lc].fstk&(1LL<<i)) && (tree[rt].fstk&(1LL<<i)))
                tree[lc].fmul=tree[lc].fmul*prime[i]%mod;
            if ((tree[rc].fstk&(1LL<<i)) && (tree[rt].fstk&(1LL<<i)))
                tree[rc].fmul=tree[rc].fmul*prime[i]%mod;
    
            if ((tree[lc].stk&(1LL<<i)) && (tree[rt].fstk&(1LL<<i)))
                tree[lc].mul=tree[lc].mul*prime[i]%mod;
            if ((tree[rc].stk&(1LL<<i)) && (tree[rt].fstk&(1LL<<i)))
                tree[rc].mul=tree[rc].mul*prime[i]%mod;
        }
        tree[lc].fstk|=tree[rt].fstk; tree[rc].fstk|=tree[rt].fstk;
        tree[lc].fmul=tree[lc].fmul*tree[rt].fmul%mod;
        tree[rc].fmul=tree[rc].fmul*tree[rt].fmul%mod;
        tree[lc].orig=tree[rt].orig*tree[lc].orig%mod;
        tree[rc].orig=tree[rt].orig*tree[rc].orig%mod;
    
        
        tree[lc].stk|=tree[rt].fstk; tree[rc].stk|=tree[rt].fstk;
        tree[lc].mul=(tree[lc].mul*tree[rt].fmul%mod)*qpow(tree[rt].orig,tree[lc].r-tree[lc].l)%mod;
        tree[rc].mul=(tree[rc].mul*tree[rt].fmul%mod)*qpow(tree[rt].orig,tree[rc].r-tree[rc].l)%mod;
        tree[rt].fstk=0;tree[rt].fmul=1;tree[rt].orig=1;
    }
    
    void build(int l,int r,int rt)
    {
        tree[rt].stk=0;  tree[rt].mul=1;
        tree[rt].fstk=0; tree[rt].fmul=1;
        tree[rt].orig=1;
        tree[rt].l=l; tree[rt].r=r;
        if (l==r){
            int x;
            scanf ("%d",&x);
            for (int i=0; i<cnt; i++){
                if (x==1) break;
                if (x%prime[i]) continue;
                tree[rt].stk|=1LL<<i;
                x/=prime[i];
                while (!(x%prime[i])) tree[rt].mul=tree[rt].mul*prime[i]%mod,x/=prime[i];
            }
            return;
        }
        int mid=(l+r)>>1;
        build(lson);build(rson);
        push_up(rt);
    }
    
    void update(int l,int r,int rt,int L,int R,int val)
    {
        if (l>=L && r<=R){
            ll tmp=0,s=1;
            int x=val;
            tree[rt].orig=tree[rt].orig*val%mod;
            for (int i=0; i<cnt; i++){
                if (x==1) break;
                if (x%prime[i]) continue;
                tmp|=1LL<<i;
                x/=prime[i];
                while (!(x%prime[i])) s=s*prime[i]%mod,x/=prime[i];
            }
            for (int i=0; i<cnt; i++){
                if ((tree[rt].fstk&(1LL<<i)) && (tmp&(1LL<<i)))
                    tree[rt].fmul=tree[rt].fmul*prime[i]%mod;
                if ((tree[rt].stk&(1LL<<i)) && (tmp&(1LL<<i)))
                    tree[rt].mul=tree[rt].mul*prime[i]%mod;
            }
            tree[rt].fstk|=tmp;
            tree[rt].fmul=s*tree[rt].fmul%mod;
            tree[rt].stk|=tmp;
            tree[rt].mul=(tree[rt].mul*s%mod)*qpow(val,r-l)%mod;
            return;
        }
        int mid=(l+r)>>1;
        if (tree[rt].fstk) push_down(rt);
        if (mid>=L) update(lson,L,R,val);
        if (mid<R) update(rson,L,R,val);
        push_up(rt);
    }
    
    ll query(int l,int r,int rt,int L,int R)
    {
        ll ans=1;
        if (l>=L && r<=R){
            ll tmp=1;
            for (int i=0; i<cnt; i++){
                if (tree[rt].stk&(1LL<<i) && !(yes_stk&(1LL<<i))) {
                    tmp=tmp*(prime[i]-1)%mod;
                    yes_stk|=1LL<<i;
                }
                else if (tree[rt].stk&(1LL<<i) && (yes_stk&(1LL<<i)))
                    tmp=tmp*prime[i]%mod;
                //if (L==4 && R==5)printf("yes_stk:%d %lld %lld 
    ",prime[i],tmp,yes_stk );
            }
            tmp=tmp*tree[rt].mul%mod;
            return tmp;
        }
        int mid=(l+r)>>1;
        if (tree[rt].fstk) push_down(rt);
        if (mid>=L) ans=ans*query(lson,L,R)%mod;
        if (mid<R) ans=ans*query(rson,L,R)%mod;
        return ans%mod;
    }
    
    int main(int argc, char const *argv[])
    {
        int m=300;
        int s=sqrt(m);
        for (int i=2; i<=s; i++)
            if (!vis[i])
                for (int j=i*i; j<=m; j+=i)
                    vis[j]=1;
        for (int i=2; i<=m; i++)
            if (!vis[i]) prime[cnt++]=i;
        int n,q;
        scanf ("%d%d",&n,&q);
        build(1,n,1);
        while (q--){
            int l,r,x;
            char s[15];
            scanf ("%s%d%d",s,&l,&r);
            yes_stk=0;
            if (s[0]=='M'){
                scanf ("%d",&x);
                update(1,n,1,l,r,x);
            }
            else {
                printf ("%lld
    ",query(1,n,1,l,r));
            }
        }
        return 0;
    }
    View Code

    然后,就开始想优化了,最后能够把枚举的去掉,然后。。。。。想了想,$(p_i-1)p_i^{k_i-1}$不就是$p_i^{k_i}/p_i*(p_i-1)$吗,那么我们直接维护乘积和状态就好了,由于数据只有300,我们完全可以预处理出每个数的素因子状态,那么枚举的62次就可以直接不用了,我们再最后得出结果的时候在判断就可以了。由于中间有除法,所以还要先预处理出每个数的逆元,不过这并不费事。。。

    以下是AC代码:

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    #define lc rt<<1
    #define rc rt<<1|1
    typedef long long ll;
    const int mac=4e5+10;
    const int mod=1e9+7;
    
    int a[mac],vis[350],prime[100],cnt=0;
    int inv[350];
    ll yes_stk=0,every_stk[350];
    struct node
    {
        int l,r;
        ll stk,fstk;
        int mul,fmul;
    }tree[mac<<2];
    
    int qpow(int a,int b)
    {
        int ans=1;
        a%=mod;
        while (b){
            if (b&1) ans=1LL*ans*a%mod;
            a=1LL*a*a%mod;
            b>>=1;
        }
        return ans%mod;
    }
    
    void push_up(int rt)
    {
        tree[rt].mul=1LL*tree[lc].mul*tree[rc].mul%mod;
        tree[rt].stk=tree[lc].stk|tree[rc].stk;
    }
    
    void push_down(int rt)
    {
        tree[lc].fstk|=tree[rt].fstk; tree[rc].fstk|=tree[rt].fstk;
        tree[lc].fmul=1LL*tree[lc].fmul*tree[rt].fmul%mod;
        tree[rc].fmul=1LL*tree[rc].fmul*tree[rt].fmul%mod;
    
        
        tree[lc].stk|=tree[rt].fstk; tree[rc].stk|=tree[rt].fstk;
        tree[lc].mul=1LL*tree[lc].mul*qpow(tree[rt].fmul,tree[lc].r-tree[lc].l+1)%mod;
        tree[rc].mul=1LL*tree[rc].mul*qpow(tree[rt].fmul,tree[rc].r-tree[rc].l+1)%mod;
        tree[rt].fstk=0;tree[rt].fmul=1;
    }
    
    void build(int l,int r,int rt)
    {
        tree[rt].stk=0;  tree[rt].mul=1;
        tree[rt].fstk=0; tree[rt].fmul=1;
        tree[rt].l=l; tree[rt].r=r;
        if (l==r){
            int x;
            scanf ("%d",&x);
            tree[rt].stk|=every_stk[x];
            tree[rt].mul=x;
            return;
        }
        int mid=(l+r)>>1;
        build(lson);build(rson);
        push_up(rt);
    }
    
    void update(int l,int r,int rt,int L,int R,int val)
    {
        if (l>=L && r<=R){
            tree[rt].fstk|=every_stk[val];
            tree[rt].fmul=1LL*val*tree[rt].fmul%mod;
            tree[rt].stk|=every_stk[val];
            tree[rt].mul=1LL*tree[rt].mul*qpow(val,r-l+1)%mod;
            return;
        }
        int mid=(l+r)>>1;
        if (tree[rt].fstk) push_down(rt);
        if (mid>=L) update(lson,L,R,val);
        if (mid<R) update(rson,L,R,val);
        push_up(rt);
    }
    
    int query(int l,int r,int rt,int L,int R)
    {
        int ans=1;
        if (l>=L && r<=R){
            yes_stk|=tree[rt].stk;
            return tree[rt].mul;
        }
        int mid=(l+r)>>1;
        if (tree[rt].fstk) push_down(rt);
        if (mid>=L) ans=1LL*ans*query(lson,L,R)%mod;
        if (mid<R) ans=1LL*ans*query(rson,L,R)%mod;
        return ans%mod;
    }
    
    int main(int argc, char const *argv[])
    {
        int m=300;
        int s=sqrt(m);
        for (int i=2; i<=s; i++)
            if (!vis[i])
                for (int j=i*i; j<=m; j+=i)
                    vis[j]=1;
        for (int i=2; i<=m; i++)
            if (!vis[i]) prime[cnt++]=i;
    
        every_stk[1]=0;
        for (int i=2; i<=300; i++){
            ll tmp=0;
            int x=i;
            for (int j=0; j<cnt; j++)
                if (x%prime[j]) continue;
                else {
                    tmp|=1LL<<j;
                    while (!(x%prime[j])) x/=prime[j];
                }
            every_stk[i]=tmp;
        }
    
        for (int i=2; i<=300; i++) 
            inv[i]=qpow(i,mod-2);
        int n,q;
        scanf ("%d%d",&n,&q);
        build(1,n,1);
        while (q--){
            int l,r,x;
            char s[15];
            scanf ("%s%d%d",s,&l,&r);
            yes_stk=0;
            if (s[0]=='M'){
                scanf ("%d",&x);
                update(1,n,1,l,r,x);
            }
            else {
                int ans=query(1,n,1,l,r);
                for (int i=0; i<cnt; i++)
                    if (yes_stk&(1LL<<i)){
                        ans=(1LL*ans*inv[prime[i]]%mod)*(prime[i]-1)%mod;
                    }
                        
                printf ("%d
    ",ans);
            }
        }
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    vs2008.net多语言实现方法
    C#中 Process的扩展类ProcessExtensions
    C#获取当前系统信息的类
    非常好用的GridView控件yyControls中的SmartGridView
    Android提供两个常用的消息弹出框【Toast和Alert】
    [置顶] Asp.net中实现多语言的Page的扩展的基类
    C# word类库
    在系统出现未处理的错误时,在Global的Application_Error记录下错误
    向大家推荐一个非常好用的JS日历控件My97DatePicker
    网页代码测试工具集合
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13288990.html
Copyright © 2011-2022 走看看