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

[六省联考2017]相逢是问候

时间:2019-09-20 15:11:31      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:pac   cpp   不同   进入   return   efi   递归   tchar   一个   

题意

给一个序列,支持两个操作:将一段区间中的每一个\(a_i\)赋值为\(c^{a_i}\)\(c\) 给定;区间求和,对\(mod\)取模,不保证\(mod\)为质数

思路

显然线段树,然而此题先要单点修改

计算中指数会非常大,但是本题\(mod\)又不是质数,于是可以套用欧拉定理的推论:

\(a^{b}≡a^{b\% \varphi(p)+\varphi(p)},(mod\) \(p)\)

由于c不变,所以赋值操作进行了几次之后就会变成求:

\(c^{c^{c^{a_i}}}\% mod=\) \(c^{c^{c^{a_i}}\% \varphi(mod)+\varphi(mod)}\%mod\)

可以看出这是一个递归形式,即求

\(c^{c^{a_i}}\% \varphi(mod)\)

一直递归下去,可以(不会)证明\(log\)次左右后\(\varphi\)将为1,所以当一个点计算了\(log\)次之后,再对它进行赋值操作就不会改变它的值了

预处理出\(\varphi\),对于修改操作,直接暴力修改,当一个区间中最小的修改次数都大于了不同的\(\varphi\)的个数,就没有必要进入这个区间了

对于单点修改,直接递归求解即可,这个操作复杂度为\(log^2n\)

整个算法复杂度为线段树*单点修改,即\(O(nlog^3n)\)可能可以通过此题,可以预处理出\(c\)的幂来去掉一个\(log\)(由于指数很大,所以需要将指数拆成两部分分别预处理出c的幂,具体见代码)

Code

#include<bits/stdc++.h>
#define N 50005
#define re register
#define Min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m;
ll mod,phi[100],c,a[N],cnt;
ll sum[N<<2],t[N<<2],pow1[N][100],pow2[N][100];
bool tag1[N][100],tag2[N][100],flag;

template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
ll quickpow(ll a,ll b,ll mod)
{
    ll ret=1;
    while(b)
    {
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}
ll ph(ll x)
{
    ll ret=x;
    for(int i=2;i*i<=x;++i)
    {
        if(x%i==0)
        {
            while(x%i==0) x/=i;
            ret=ret*(i-1)/i;
        }
    }
    if(x!=1) ret=ret*(x-1)/x;
    return ret;
}

void pushup(int rt)
{
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
    t[rt]=Min(t[rt<<1],t[rt<<1|1]);
}
inline ll calc(ll v,ll id)
{
    flag=0;
    ll v1=v%10000,v2=v/10000,ret=pow1[v1][id]*pow2[v2][id];
    if(ret>=phi[id]) ret=ret%phi[id],flag=1;
    flag|=tag1[v1][id]|tag2[v2][id];
    return ret;
}
ll dfs(ll vi,int deep,int lim)
{
    flag=0;
    if(deep==lim)
    {
        if(vi>=phi[deep]) flag=1,vi%=phi[deep];
        return vi;
    }
    ll ci=dfs(vi,deep+1,lim);
    return calc(flag?ci+phi[deep+1]:ci,deep);
}
void init()
{
    phi[cnt=0]=mod;
    while(phi[cnt]!=1) ++cnt,phi[cnt]=ph(phi[cnt-1]);
    phi[++cnt]=1;
    for(int i=0;i<=cnt;++i)
    {
        pow1[0][i]=1;
        for(int j=1;j<=10000;++j)
        {
            pow1[j][i]=pow1[j-1][i]*c;
            if(pow1[j][i]>=phi[i])
            {
                pow1[j][i]%=phi[i];
                tag1[j][i]=true;
            }
            tag1[j][i]|=tag1[j-1][i];
        }
    }
    for(int i=0;i<=cnt;++i)
    {
        pow2[0][i]=1;
        tag2[1][i]=tag1[10000][i];
        for(int j=1;j<=10000;++j)
        {
            pow2[j][i]=pow2[j-1][i]*pow1[10000][i];
            if(pow2[j][i]>=phi[i])
            {
                pow2[j][i]%=phi[i];
                tag2[j][i]=true;
            }
            tag2[j][i]|=tag2[j-1][i];
        }
    }
}
void modify(int rt,int l,int r,int x,int y)
{
    if(t[rt]>=cnt) return;
    if(l==r)
    {
        ++t[rt];
        sum[rt]=dfs(a[l],0,t[rt]);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) modify(rt<<1,l,mid,x,y);
    if(y>mid) modify(rt<<1|1,mid+1,r,x,y);
    pushup(rt);
}
ll query(int rt,int l,int r,int x,int y)
{
    if(x<=l&&r<=y) return sum[rt];
    int mid=(l+r)>>1;
    ll ret=0;
    if(x<=mid) ret+=query(rt<<1,l,mid,x,y);
    if(y>mid) ret=(ret+query(rt<<1|1,mid+1,r,x,y))%mod;
    return ret;
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        sum[rt]=a[l];
        t[rt]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}

int main()
{
//  freopen("verbinden.in","r",stdin);
//  freopen("verbinden.out","w",stdout);
    read(n);read(m);read(mod);read(c);
    for(re int i=1;i<=n;++i) read(a[i]);
    
    init();
    build(1,1,n);
    
    while(m--)
    {
        int k,l,r;
        read(k);read(l);read(r);
        if(!k) modify(1,1,n,l,r);
        else printf("%lld\n",query(1,1,n,l,r));
    }
    return 0;
}

[六省联考2017]相逢是问候

标签:pac   cpp   不同   进入   return   efi   递归   tchar   一个   

原文地址:https://www.cnblogs.com/Chtholly/p/11557314.html

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