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


    题意

    给一个序列,支持两个操作:将一段区间中的每一个(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
    ",query(1,1,n,l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    微信小程序如何获取UnionId详细版---Crypto.js解密
    微信小程序获取用户unionId
    pymysql的使用
    OpenCV 磨皮-Python
    python 识别图片中的人脸,并裁剪人脸,将图片转化成固定大小,并将图片再按照自己的后缀名存储起来
    python遍历文件夹中的所有jpg文件
    numpy matrix 与ndarray的区别
    netty: 解决粘包拆包: 分隔符DelimiterBasedFrameDecoder,定长消息FixedLengthFrameDecoder
    commons-dbutils工具栏的编写
    commons-dbutils 字段名称转换,支持驼峰字段名
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11557314.html
Copyright © 2020-2023  润新知