[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)\ \ +b\mod\varphi(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\n",Query(1,l,r));
    }
    return 0;
}
posted @ 2017-05-21 23:44  FallDream  阅读(683)  评论(0编辑  收藏  举报