[Shoi2017]相逢是问候

传送门

这种“暴力线段树”可以考虑一下是不是有什么特殊性质。

对于这道题什么要知道:

可能这里写得比较清楚(摘自

感觉就是一个迭代的过程。

而一个数在操作k次之后就可以不用再操作了。

然后使用欧拉定理的时候要特判一下:

x>=phi时,最后要加一个phi

小于则不加。

预处理出所有的phi,记得最后一个phi为1。

#include<bits/stdc++.h>
#define LL long long
#define N 50003
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
LL n,m,p,c;
LL num=0;
LL a[N],P[N];
int ok=0;
LL quick(LL a,LL x,LL mod)
{
    LL ans=1;
    while(x)
    {
        if(x&1)ans=ans*a;
        a=a*a;x>>=1;
        if(ans>=mod)ok=1,ans%=mod;
        if(a>=mod)ok=1,a%=mod;
    }
    return ans;
}
int phi(int x)
{
    int ans=x;
    for(int i=2;i*i<=x;++i)
    {
        if(x%i==0)
        {
            ans=ans/i*(i-1);
            while(x%i==0)x/=i;
        }
    }
    if(x!=1)ans=ans/x*(x-1);
    return ans;
}
LL sum[N<<2],ge[N<<2];
void pushup(int k)
{
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
    ge[k]=min(ge[k<<1],ge[k<<1|1]);
}
void build(int k,int l,int r)
{
    if(l==r){sum[k]=a[l]%p;return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    pushup(k);
}
LL query(int k,int L,int R,int l,int r)
{
    LL ans=0;
    if(L>=l&&R<=r)return sum[k];
    int mid=(L+R)>>1;
    if(l<=mid)
    {
        ans+=query(k<<1,L,mid,l,r);
        if(ans>=p)ans%=p;
    }
    if(r>mid)
    {
        ans+=query(k<<1|1,mid+1,R,l,r);
        if(ans>=p)ans%=p;
    }
    return ans%p;
}
LL cal(LL x,LL times)
{
    if(x>P[times]) x=x%P[times]+P[times];
    for(int i=times;i>=1;--i)//类似迭代求解
    {
        ok=0;//特判一下
        x=quick(c,x,P[i-1]);
        if(ok) x+=P[i-1];
    }
    return x;
}
void modify(int k,int L,int R,int l,int r)
{
    if(ge[k]>=num)return;//超过上限次数就不会再变了
    if(L==R)
    {
        sum[k]=cal(a[L],++ge[k])%p;
        return ;
    }
    int mid=(L+R)>>1;
    if(l<=mid)modify(k<<1,L,mid,l,r);
    if(r>mid)modify(k<<1|1,mid+1,R,l,r);
    pushup(k);
}
int main()
{
 // freopen("verbinden.in","r",stdin);
//  freopen("verbinden.out","w",stdout);
    n=read(),m=read(),p=read(),c=read();
    int q=p;
    num=0;
    P[0]=q;
    while(q!=1)//预处理出phi
    {
        q=P[++num]=phi(q);
    }
    P[++num]=1;
    int flagg=0;
    for(int i=1;i<=n;++i)a[i]=read();
    build(1,1,n);
    for(int i=1;i<=m;++i)
    {
        int op=read(),l=read(),r=read();
        if(op==0)
        {
            modify(1,1,n,l,r);//a[i]=quick(c,a[i]);
        }
        else if(op==1)
        {
            LL ans=0;
            printf("%lld\n",query(1,1,n,l,r)%p);
        }
    }
} 

原文地址:https://www.cnblogs.com/yyys-/p/11544402.html

时间: 2024-10-12 00:15:39

[Shoi2017]相逢是问候的相关文章

bzoj4869 [Shoi2017]相逢是问候

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4869 [题解] 发现好像没有办法普通维护. 给小盆友们江数论的时候江过x^m mod p = x^(m mod phi(p)) mod p 发现一个数进行phi操作最多log次. 暴力就行啦qwq 注意就是phi的那个最后要补一个phi[++pn] = 1. 为什么呢?因为phi(1) = 1(展开到最后,还要多展开一层(!)) 那么就行啦! 复杂度不大会分析qwq 照理性分析可能是log

【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理

Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为 这个结果可能会很大,所以你只需要输出结

bzoj 4869: [Shoi2017]相逢是问候

Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为 这个结果可能会很大,所以你只需要输出结

[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)

4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1313  Solved: 471[Submit][Status][Discuss] Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每

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

相逢是问候 2017-09-09 Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为这个结果可

【BZOJ4869】相逢是问候 [线段树]

相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值

【BZOJ4869】相逢是问候(线段树,欧拉定理)

[BZOJ4869]相逢是问候(线段树,欧拉定理) 题面 BZOJ 题解 根据欧拉定理递归计算(类似上帝与集合的正确用法) 所以我们可以用线段树维护区间最少的被更新的多少次 如果超过了\(\varphi\)的限制 就不用再计算了 如果需要计算就每次暴力算 这样的复杂度\(O(nlog^2)\) #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<

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

传送门 题解 扩展欧拉定理. 线段树维护,已经全改到底了的节点就不管,不然暴力修改下去. //Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<queue> #include<cmath> const int N=5

[BZOJ 4869][SXOI2017]相逢是问候(扩展欧拉定理+线段树)

Description Informatik verbindet dich und mich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为 这个结果可能会很大,所以你只需