[Shoi2017]相逢是问候

传送门

这种“暴力线段树”可以考虑一下是不是有什么特殊性质。

对于这道题什么要知道:

 可能这里写得比较清楚(摘自

感觉就是一个迭代的过程。

而一个数在操作k次之后就可以不用再操作了。

然后使用欧拉定理的时候要特判一下:

x>=phi时,最后要加一个phi

小于则不加。

 

 预处理出所有的phi,记得最后一个phi为1。

#include<bits/stdc++.h>
#define LL long long
#define N 50003
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
LL n,m,p,c;
LL num=0;
LL a[N],P[N];
int ok=0;
LL quick(LL a,LL x,LL mod)
{
    LL ans=1;
    while(x)
    {
        if(x&1)ans=ans*a;
        a=a*a;x>>=1;
        if(ans>=mod)ok=1,ans%=mod;
        if(a>=mod)ok=1,a%=mod;
    }
    return ans;
}
int phi(int x)
{
    int ans=x;
    for(int i=2;i*i<=x;++i)
    {
        if(x%i==0)
        {
            ans=ans/i*(i-1);
            while(x%i==0)x/=i;
        }
    }
    if(x!=1)ans=ans/x*(x-1);
    return ans; 
}
LL sum[N<<2],ge[N<<2];
void pushup(int k)
{
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
    ge[k]=min(ge[k<<1],ge[k<<1|1]);
}
void build(int k,int l,int r)
{
    if(l==r){sum[k]=a[l]%p;return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    pushup(k);
}
LL query(int k,int L,int R,int l,int r)
{
    LL ans=0;
    if(L>=l&&R<=r)return sum[k];
    int mid=(L+R)>>1;
    if(l<=mid)
    {
        ans+=query(k<<1,L,mid,l,r);
        if(ans>=p)ans%=p;
    }
    if(r>mid)
    {
        ans+=query(k<<1|1,mid+1,R,l,r);
        if(ans>=p)ans%=p;
    }
    return ans%p;
}
LL cal(LL x,LL times)
{
    if(x>P[times]) x=x%P[times]+P[times];
    for(int i=times;i>=1;--i)//类似迭代求解 
    {
        ok=0;//特判一下 
        x=quick(c,x,P[i-1]);
        if(ok) x+=P[i-1];
    } 
    return x;
}
void modify(int k,int L,int R,int l,int r)
{
    if(ge[k]>=num)return;//超过上限次数就不会再变了 
    if(L==R)
    {
        sum[k]=cal(a[L],++ge[k])%p;
        return ;
    } 
    int mid=(L+R)>>1;
    if(l<=mid)modify(k<<1,L,mid,l,r);
    if(r>mid)modify(k<<1|1,mid+1,R,l,r);
    pushup(k);
}
int main()
{ 
 // freopen("verbinden.in","r",stdin);
//  freopen("verbinden.out","w",stdout);
    n=read(),m=read(),p=read(),c=read();
    int q=p;
    num=0;
    P[0]=q;
    while(q!=1)//预处理出phi 
    {
        q=P[++num]=phi(q);
    }
    P[++num]=1;
    int flagg=0;
    for(int i=1;i<=n;++i)a[i]=read();
    build(1,1,n);
    for(int i=1;i<=m;++i)
    {
        int op=read(),l=read(),r=read();
        if(op==0)
        {
            modify(1,1,n,l,r);//a[i]=quick(c,a[i]);
        }
        else if(op==1)
        {
            LL ans=0;
            printf("%lld\n",query(1,1,n,l,r)%p);
        }
    }
} 
View Code

猜你喜欢

转载自www.cnblogs.com/yyys-/p/11544402.html