zoukankan      html  css  js  c++  java
  • [bzoj4869][Shoi2017]相逢是问候

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    B 君希望以维护一个长度为 n 的数组,这个数组的下标为从 1 到 n 的正整数。

    一共有 m 个操作,可以分为两种:

    • 0 l r 表示将第 l 个到第 r 个数(al al+1 ... ar)中的每一个数 ai 替换为$c^{ai}$,即 c 的 ai 次方,其中 c 是输入的一个常数,也就是执行赋值

    $ai=c^{ai}$

    • 1 l r 求第 l 个到第 r 个数的和,也就是输出:$sum_{i=l}^{r} ai$

    因为这个结果可能会很大,所以你只需要输出结果 mod p 的值即可。

     1 ≤ n ≤ 50000; 1 ≤ m ≤ 50000; 1 ≤ p ≤ 100000000; 0 < c <p; 0 ≤ ai < p。

    这道题真的折磨人....

    底数与模数不互质,不能直接用欧拉定理

    扩展欧拉定理 当$b>varphi(m)$时 $ a^{b}= a^{{ varphi(m) +bmodvarphi(m) }}(mod m)  $

    然后递归下去就能计算。

    通过这个式子可以发现,一个数在操作最多log次之后就会变成定值,所以直接暴力计算即可。

    然后直接计算是log三方的,所以考虑把快速幂的log压掉  

    因为指数不超过2p,所以预处理每个模数时c的0到$2^{14}$次方的答案,和c的$i*2^{14},i=1-2^{14}$次方的答案,查询时候直接并起来即可。

    然后有个地方就是 phi(1)=1 所以最后要加上去一个1,不然会wa 233

    复杂度$nlog^{2}n$

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define MN 50000
    #define N 16384
    #define ll long long
    #define rint register int
    #define getchar() (*S++)
    char B[1<<26],*S=B;
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    bool b[10005];int s[10005],cnt=0;
    int n,m,c,p,a[MN+5],Phi[30],rt,Rt,num[MN+5],Mx,pw[40][N+5],Pw[40][N+5];
    struct Tree{int l,r,val,x;}T[MN*4+5];
    inline void pushup(int x){int l=x<<1,r=x<<1|1;T[x].val=T[l].val+T[r].val;T[x].x=(T[l].x+T[r].x)%p;}
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)){T[x].x=a[l];T[x].val=1;return;}
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        pushup(x);
    }
    inline int pow(int k,int mod){return !k?1:1LL*Pw[mod][k&(N-1)]*pw[mod][k>>14]%Phi[mod];}
    
    inline int Calc(int x,int p)
    {
        int res=x%Phi[p];bool b=x>=Phi[p];
        for(int i=p;i;--i)
        {
            if(b) res+=Phi[i];int pre=res;
            res=pow(res,i-1);
            if(!b && res >= log(Phi[i-1]/log(c))) b=1;
        }
        return res;
    }
    
    inline void Mark(int x)
    {
        if(T[x].l==T[x].r)
        {
            T[x].x=Calc(a[T[x].l],++num[T[x].l]);
            if(num[T[x].l]==Mx) T[x].val=0;
        }
        else
        {
            if(T[x<<1].val) Mark(x<<1);
            if(T[x<<1|1].val) Mark(x<<1|1);
            pushup(x);
        }
    }
    
    void Modify(int x,int l,int r)
    {
        if(!T[x].val) return;
        if(T[x].l==l&&T[x].r==r) {Mark(x);return;}
        int mid=(T[x].l+T[x].r)>>1;
        if(r<=mid) Modify(x<<1,l,r);
        else if(l>mid) Modify(x<<1|1,l,r);
        else Modify(x<<1,l,mid),Modify(x<<1|1,mid+1,r);
        pushup(x);
    }
    
    int Query(int x,int l,int r)
    {
        if(T[x].l==l&&T[x].r==r) return T[x].x;
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) return Query(x<<1,l,r);
        else if(l>mid) return Query(x<<1|1,l,r);
        else return (Query(x<<1,l,mid)+Query(x<<1|1,mid+1,r))%p;
    }
    
    int GetPhi(int x)
    {
        int PHI=x;
        for(int i=1;i<=cnt&&s[i]<=x;++i)
            if(x%s[i]==0)
            {
                PHI=PHI/s[i]*(s[i]-1);
                do x/=s[i]; while(x%s[i]==0);
            }
        if(x>1) PHI=PHI/x*(x-1);
        return PHI;
    }
    
    int main()
    {
        fread(B,1,1<<26,stdin);
        n=read();m=read();p=read();c=read();
        for(rint i=1;i<=n;++i) a[i]=read();
        build(1,1,n);int sq=sqrt(p);
        for(int i=2;i<=sq;++i)
        {
            if(!b[i]) s[++cnt]=i;
            for(int j=1;s[j]*i<=sq;++j)
            {
                b[s[j]*i]=1;
                if(i%s[j]==0) break;
            }
        }
        for(Phi[Mx=0]=p;Phi[Mx]>1;++Mx,Phi[Mx]=GetPhi(Phi[Mx-1]));Phi[++Mx]=1;
        for(rint i=0;i<Mx-1;++i)
        { 
            Pw[i][0]=pw[i][0]=1;
            for(rint j=1;j<=N;++j)
                Pw[i][j]=1LL*Pw[i][j-1]*c%Phi[i];
            for(rint j=1;j<=N;++j)
                pw[i][j]=1LL*pw[i][j-1]*Pw[i][N]%Phi[i];
        }
        for(rint i=1;i<=m;++i)
        {
            int op=read(),l=read(),r=read();
            if(!op) Modify(1,l,r);
            else printf("%d
    ",Query(1,l,r));
        }
        return 0;
    }
  • 相关阅读:
    OpenStack Trail 部署文档(二)基础服务部署
    OpenStack Trail 部署文档(一)环境规划
    OpenStack Trail 部署文档
    配置kubectl在Mac(本地)远程连接Kubernetes集群
    elasticsearch*3 + Es-Head + kibana Docker集群
    Flex 布局教程:语法篇
    PHP 数组 array_merge 和 数组 + 加号操作的区别
    Redis分布式锁
    Mysql中Exists和In的使用
    让PHP7达到最高性能的几个Tips
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4869.html
Copyright © 2011-2022 走看看