bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

Posted 日拱一卒 功不唐捐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=4869

 

欧拉降幂+线段树,每个数最多降log次,模数就会降为1

 

技术分享图片
#include<cmath>
#include<cstdio>
#include<iostream>

using namespace std;

#define N 50001

int n,m,p,c;
int a[N];

int sum[N<<2];
int tag[N<<2];

int lim,pi[101],phi[101];

int ans;

bool flag;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-0; c=getchar(); }
}

int Pow(int a,int b,int mod)
{
    int res=1;
    while(b)
    {
        if(b&1)
        {
            if(1LL*res*a>=mod) flag=true;
            res=1LL*res*a%mod;    
        }
        if(1LL*a*a>=mod) flag=true;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return res;
}

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

int get_phi(int x)
{
    int y=sqrt(x);
    int ph=x;
    for(int i=2;i<=y;++i)
        if(!(x%i))
        {
            while(!(x%i)) x/=i;
            ph=ph/i*(i-1);
        }
    if(x>1) ph=ph/x*(x-1);
    return ph;
}

int f(int dep,int x)
{
    int tmp=x;
    if(tmp>=phi[dep]) tmp=tmp%phi[dep]+phi[dep];
    for(int i=dep;i;--i)
    {
        flag=false;
        tmp=Pow(c,tmp,pi[i]);
        if(flag) tmp+=phi[i-1];
    }
    return tmp;
}

void change(int k,int l,int r,int opl,int opr)
{
    if(tag[k]>=lim) return;
    if(l==r)
    {
        tag[k]++;
        sum[k]=f(tag[k],a[l]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr);
    tag[k]=min(tag[k<<1],tag[k<<1|1]);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        ans+=sum[k];
        ans%=p;
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    read(n); read(m); read(p); read(c);
    for(int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    int tmp=p;
    while(pi[lim]!=1)
    {
        pi[++lim]=tmp;
        phi[lim]=get_phi(tmp);
        tmp=phi[lim];
    }
    int ty,l,r;
    while(m--)
    {
        read(ty); read(l); read(r);
        if(!ty) change(1,1,n,l,r);
        else 
        {
            ans=0;
            query(1,1,n,l,r);
            printf("%d\n",ans);
        }
    }
    return 0;
}
迭代降幂

 

技术分享图片
#include<cmath>
#include<cstdio>
#include<iostream>

using namespace std;

#define N 50001

int n,m,p,c;
int a[N];

int sum[N<<2];
int tag[N<<2];

int lim,pi[101],phi[101];

int ans;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-0; c=getchar(); }
}

int Pow(int a,int b,int mod)
{
    int res=1;
    for(;b;a=1LL*a*a%mod,b>>=1)
        if(b&1) res=1LL*res*a%mod;
    return res;
}

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

int get_phi(int x)
{
    int y=sqrt(x);
    int ph=x;
    for(int i=2;i<=y;++i)
        if(!(x%i))
        {
            while(!(x%i)) x/=i;
            ph=ph/i*(i-1);
        }
    if(x>1) ph=ph/x*(x-1);
    return ph;
}

int f(int dep,int up,int x)
{
    if(dep==up) return Pow(c,x,pi[dep]); 
    int y=f(dep+1,up,x);
    if(!y) y=phi[dep];
    if(y<=phi[dep]) return Pow(c,y,pi[dep]);
    return Pow(c,y%phi[dep]+phi[dep],pi[dep]);
}

void change(int k,int l,int r,int opl,int opr)
{
    if(tag[k]>=lim) return;
    if(l==r)
    {
        tag[k]++;
        sum[k]=f(1,tag[k],a[l]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr);
    tag[k]=min(tag[k<<1],tag[k<<1|1]);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        ans+=sum[k];
        ans%=p;
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    //freopen("verbinden.in","r",stdin);
    //freopen("verbinden.out","w",stdout);
    read(n); read(m); read(p); read(c);
    for(int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    int tmp=p;
    while(pi[lim]!=1)
    {
        pi[++lim]=tmp;
        phi[lim]=get_phi(tmp);
        tmp=phi[lim];
    }
    int ty,l,r;
    while(m--)
    {
        read(ty); read(l); read(r);
        if(!ty) change(1,1,n,l,r);
        else 
        {
            ans=0;
            query(1,1,n,l,r);
            printf("%d\n",ans);
        }
    }
    return 0;
}
递归降幂

以上是关于bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划265:bzoj4873: [六省联考2017]寿司餐厅

bzoj千题计划266:bzoj4872: [六省联考2017]分手是祝愿

[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)

bzoj千题计划214:bzoj3589: 动态树

bzoj千题计划197:bzoj4247: 挂饰

bzoj千题计划118:bzoj1028: [JSOI2007]麻将