码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-03-11 12:05:46      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:ble   int   span   opened   tmp   div   src   ==   blog   

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]相逢是问候

标签:ble   int   span   opened   tmp   div   src   ==   blog   

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8543188.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!