P3747 [六省联考2017]相逢是问候 欧拉公式

题意:

戳这里

分析:

  • 暴力

\(O(nm\log )\) 模拟,\(p=2\) 的点判奇偶性,期望得分 \(20pts\)

  • 正解

我们发现 \(c\) 恒定,所以经过一系列操作后,每一个元素变为了 \(\large x^{c^{c^{\dots {a_i}}}}\)

我们发现这个形式很欧拉定理,因为欧拉定理对于单个数一旦累计次方超过一定程度,值就成 \(1\) 不变了,我们由已知结论得到,这个次数大约是 \(\log p\) 级别的,也就是说对于每一个元素只有前 $\log $ 次操作是有效的

所以我们预处理出来每一个数前 \(\log\) 次操作,然后按照欧拉定理分 $\log $ 层,所以预处理的复杂度是 \(O(n\log^2)\)

(因为我们使用了光速幂,所以复杂度是 \(2\) 只 $\log $)

然后我们需要线段树维护区间修改操作次数的最小值,一旦区间修改操作大于 $ \log$ 直接返回 ,然后顺便维护区间和值

代码:

#include<bits/stdc++.h>
#define lc rt<<1
#define rc rt<<1|1
using namespace std;

namespace zzc
{
    long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const long long maxn = 5e4+5;
    const long long maxs = 1e4+5;
    long long cnt[maxn<<2],v[maxn<<2];    
    long long s1[maxs][30],s2[maxs][30],f[maxn][30][30],a[maxn],g[30],phi[30];
    bool b1[maxs][30],b2[maxs][30],b[maxn][30][30];
    long long n,m,p,c,len;

    long long get_phi(long long x)
    {
        long long res=x;
        for(int i=2;i*i<=x;i++)
        {
            if(x%i) continue;
            res=res*(i-1)/i;
            while(x%i==0) x/=i;
        }
        if(x>1) res=res*(x-1)/x;
        return res;
    }

    void init()
    {
        long long tmp=p;
        phi[0]=tmp;
        while(tmp!=1)
        {
            tmp=get_phi(tmp);
            phi[++len]=tmp;
        }
        phi[++len]=1;
        for(int i=0;i<=len;i++) g[i]=__gcd(c,phi[i]);

        //¹âËÙÃÝ
        for(int j=0;j<=len;j++)
        {
            s2[0][j]=1;
            for(int i=1;i<=10000;i++)
            {
                s2[i][j]=s2[i-1][j]*c;
                if(s2[i][j]>=phi[j])
                {
                    s2[i][j]%=phi[j];
                    b2[i][j]=true;
                }
                b2[i][j]|=b2[i-1][j];
            }
        }

        for(int j=0;j<=len;j++)
        {
            s1[0][j]=1;
            b1[1][j]=b2[10000][j];
            for(int i=1;i<=10000;i++)
            {
                s1[i][j]=s1[i-1][j]*s2[10000][j];
                if(s1[i][j]>=phi[j])
                {
                    s1[i][j]%=phi[j];
                    b1[i][j]=true;
                }
                b1[i][j]|=b1[i-1][j];
            }
        }
        
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=len;j++)
            {
                f[i][0][j]=a[i]%phi[j];
                if(a[i]>=phi[j]) b[i][0][j]=true;
            }
            for(int j=1;j<=len;j++)
            {
                f[i][j][len]=0;
                for(int k=0;k<len;k++)
                {
                    f[i][j][k]=s1[f[i][j-1][k+1]/10000][k]*s2[f[i][j-1][k+1]%10000][k];
                    b[i][j][k]=b1[f[i][j-1][k+1]/10000][k]|b2[f[i][j-1][k+1]%10000][k];
                    if(f[i][j][k]>=phi[k])
                    {
                        f[i][j][k]%=phi[k];
                        b[i][j][k]=true;
                    }
                    if(g[k]!=1&&b[i][j-1][k+1])
                    {
                        f[i][j][k]=f[i][j][k]*s1[phi[k+1]/10000][k]%phi[k]*s2[phi[k+1]%10000][k];
                        if(f[i][j][k]>=phi[k])
                        {
                            f[i][j][k]%=phi[k];
                            b[i][j][k]=true;
                        }
                        b[i][j][k]|=b1[phi[k+1]/10000][k]|b2[phi[k+1]%10000][k];
                    }
                }
            }
        }
        return ;
    }

    void pushup(int rt)
    {
        v[rt]=v[lc]+v[rc];
        cnt[rt]=min(cnt[lc],cnt[rc]);
    }

    void build(int rt,int l,int r)
    {
        if(l==r)
        {
            v[rt]=a[l];
            cnt[rt]=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(lc,l,mid);build(rc,mid+1,r);
        pushup(rt);
    }

    void modify(int rt,int l,int r,int ql,int qr)
    {
        if(ql>r||l>qr||cnt[rt]>=len) return ;
        if(l==r)
        {
            cnt[rt]++;
            v[rt]=f[l][cnt[rt]][0]%p;
            return ;
        }
        int mid=(l+r)>>1;
        if(cnt[lc]<len) modify(lc,l,mid,ql,qr);
        if(cnt[rc]<len) modify(rc,mid+1,r,ql,qr);
        pushup(rt);
    }

    long long query(int rt,int l,int r,int ql,int qr)
    {
        if(ql>r||qr<l) return 0;
        if(ql<=l&&r<=qr) return v[rt]%p;
        int mid=(l+r)>>1;
        return (query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr))%p;
    }

    void work()
    {
        int opt,l,r;
        n=read();m=read();p=read();c=read();
        for(int i=1;i<=n;i++) a[i]=read();
        init();
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            opt=read();l=read();r=read();
            if(opt==0) modify(1,1,n,l,r);
            else printf("%lld\n",query(1,1,n,l,r));
        }
    }
}


int main()
{
    zzc::work();
    return 0;
}
posted @ 2020-12-24 20:28  youth518  阅读(58)  评论(0编辑  收藏  举报