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

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

题面

BZOJ

题解

根据欧拉定理递归计算(类似上帝与集合的正确用法)
所以我们可以用线段树维护区间最少的被更新的多少次
如果超过了\(\varphi\)的限制
就不用再计算了
如果需要计算就每次暴力算
这样的复杂度\(O(nlog^2)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define lson (now<<1)
#define rson (now<<1|1)
#define MAX 80000
#define ll long long
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int a[MAX],C,P,n,m;
ll phi[MAX],tot;
ll Phi(ll x)
{
    ll ret=x;
    for(ll i=2;i*i<=x;++i)
        if(x%i==0)
        {
            ret=ret/i*(i-1);
            while(x%i==0)x/=i;
        }
    if(x>1)ret=ret/x*(x-1);
    return ret;
}
ll fpow(ll a,ll b,ll P)
{
    long long s=1;
    bool fl=false,f2=false;
    while(b)
    {
        if(b&1)s=1ll*s*a,fl|=f2;
        if(s>=P)fl=true,s%=P;
        a=a*a;
        if(a>=P)f2=true,a%=P;
        b>>=1;
    }
    if(fl)s+=P;
    return s;
}
struct Node{long long sum;int tt;}t[MAX<<2];
inline void Build(int now,int l,int r)
{
    if(l==r){t[now].sum=a[l]=read();return;}
    int mid=(l+r)>>1;
    Build(lson,l,mid);Build(rson,mid+1,r);
    t[now].sum=(t[lson].sum+t[rson].sum)%P;
}
ll Calc(int l,int r,ll x,ll P)
{
    if(l==r)return fpow(x,1,P);
    return fpow(C,Calc(l+1,r,x,phi[l+1]),P);
}
void Modify(int now,int l,int r,int L,int R)
{
    if(t[now].tt>=tot)return;
    if(l==r)
    {
        t[now].sum=Calc(0,++t[now].tt,a[l],P)%P;
        //t[now].sum=fpow(C,a[l],P)%P;
        //a[l]=fpow(C,a[l],phi[1]);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)Modify(lson,l,mid,L,R);
    if(R>mid)Modify(rson,mid+1,r,L,R);
    t[now].tt=min(t[lson].tt,t[rson].tt);
    t[now].sum=(t[lson].sum+t[rson].sum)%P;
}
int Query(int now,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)return t[now].sum;
    int mid=(l+r)>>1;ll ret=0;
    if(L<=mid)ret=(ret+Query(lson,l,mid,L,R))%P;
    if(R>mid)ret=(ret+Query(rson,mid+1,r,L,R))%P;
    return ret;
}
int main()
{
    n=read();m=read();P=read();C=read();
    Build(1,1,n);
    phi[0]=P;
    for(tot=1;;++tot)
    {
        phi[tot]=Phi(phi[tot-1]);
        if(phi[tot]==1)break;
    }
    phi[++tot]=1;
    while(m--)
    {
        int opt=read(),l=read(),r=read();
        if(opt)printf("%d\n",Query(1,1,n,l,r));
        else Modify(1,1,n,l,r);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8330169.html

时间: 2024-10-01 06:09:20

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

[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)中的每

【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因为 这个结果可能会很大,所以你只需要输出结

【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是 输入的一个常数,也就是执行赋值

[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因为 这个结果可能会很大,所以你只需

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

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

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

好题啊! 调了一个中午,发现有一条语句 \(RE\) 了.在 \(windows\) 下没关系,\(linux\) 下有问题,大大的问题. while(phi[tot]!=1) phi[++tot]=calc_phi(phi[tot-1]); 算是拓展欧拉定理的题吧.线段树只是一个工具,最主要还是暴力修改.因为 \(\varphi\) 不断套下去最多会有 \(\lfloor \log n\rfloor\) 层,所以我们对于每一层暴力算一遍,加上快速幂,时间复杂度 \(O(n\log^3 n)\)

bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 50001 int n,m,p,c; int a[N]; int sum[N<<2]; int tag[N<<2]; in

[六省联考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因为这个结果可

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因为 这个结果可能会很大,所以你只需要输出结