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


    题意:

    戳这里

    分析:

    • 暴力

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

    • 正解

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

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

    所以我们预处理出来每一个数前 (log) 次操作,然后按照欧拉定理分 $log $ 层,所以预处理的复杂度是 (O(nlog^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
    ",query(1,1,n,l,r));
            }
        }
    }
    
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    paip.解决Invalid byte 2 of 2byte UTF8 sequence.
    poj1157
    poj1258
    poj1160
    poj1113
    poj1159
    !!!GRETA正则表达式模板类库
    【原创】C#与C++的混合编程采用其中的第三种方法
    WinApi.cs
    C#:正则表达式30分钟入门教程
  • 原文地址:https://www.cnblogs.com/youth518/p/14186208.html
Copyright © 2020-2023  润新知