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];

int lim,pi[101],phi[101];

int ans;

bool flag;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}

int Pow(int a,int b,int mod)
{
    int res=1;
    while(b)
    {
        if(b&1)
        {
            if(1LL*res*a>=mod) flag=true;
            res=1LL*res*a%mod;
        }
        if(1LL*a*a>=mod) flag=true;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return res;
}

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

int get_phi(int x)
{
    int y=sqrt(x);
    int ph=x;
    for(int i=2;i<=y;++i)
        if(!(x%i))
        {
            while(!(x%i)) x/=i;
            ph=ph/i*(i-1);
        }
    if(x>1) ph=ph/x*(x-1);
    return ph;
}

int f(int dep,int x)
{
    int tmp=x;
    if(tmp>=phi[dep]) tmp=tmp%phi[dep]+phi[dep];
    for(int i=dep;i;--i)
    {
        flag=false;
        tmp=Pow(c,tmp,pi[i]);
        if(flag) tmp+=phi[i-1];
    }
    return tmp;
}

void change(int k,int l,int r,int opl,int opr)
{
    if(tag[k]>=lim) return;
    if(l==r)
    {
        tag[k]++;
        sum[k]=f(tag[k],a[l]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr);
    tag[k]=min(tag[k<<1],tag[k<<1|1]);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        ans+=sum[k];
        ans%=p;
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    read(n); read(m); read(p); read(c);
    for(int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    int tmp=p;
    while(pi[lim]!=1)
    {
        pi[++lim]=tmp;
        phi[lim]=get_phi(tmp);
        tmp=phi[lim];
    }
    int ty,l,r;
    while(m--)
    {
        read(ty); read(l); read(r);
        if(!ty) change(1,1,n,l,r);
        else
        {
            ans=0;
            query(1,1,n,l,r);
            printf("%d\n",ans);
        }
    }
    return 0;
}

迭代降幂

#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];

int lim,pi[101],phi[101];

int ans;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}

int Pow(int a,int b,int mod)
{
    int res=1;
    for(;b;a=1LL*a*a%mod,b>>=1)
        if(b&1) res=1LL*res*a%mod;
    return res;
}

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

int get_phi(int x)
{
    int y=sqrt(x);
    int ph=x;
    for(int i=2;i<=y;++i)
        if(!(x%i))
        {
            while(!(x%i)) x/=i;
            ph=ph/i*(i-1);
        }
    if(x>1) ph=ph/x*(x-1);
    return ph;
}

int f(int dep,int up,int x)
{
    if(dep==up) return Pow(c,x,pi[dep]);
    int y=f(dep+1,up,x);
    if(!y) y=phi[dep];
    if(y<=phi[dep]) return Pow(c,y,pi[dep]);
    return Pow(c,y%phi[dep]+phi[dep],pi[dep]);
}

void change(int k,int l,int r,int opl,int opr)
{
    if(tag[k]>=lim) return;
    if(l==r)
    {
        tag[k]++;
        sum[k]=f(1,tag[k],a[l]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr);
    tag[k]=min(tag[k<<1],tag[k<<1|1]);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        ans+=sum[k];
        ans%=p;
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    //freopen("verbinden.in","r",stdin);
    //freopen("verbinden.out","w",stdout);
    read(n); read(m); read(p); read(c);
    for(int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    int tmp=p;
    while(pi[lim]!=1)
    {
        pi[++lim]=tmp;
        phi[lim]=get_phi(tmp);
        tmp=phi[lim];
    }
    int ty,l,r;
    while(m--)
    {
        read(ty); read(l); read(r);
        if(!ty) change(1,1,n,l,r);
        else
        {
            ans=0;
            query(1,1,n,l,r);
            printf("%d\n",ans);
        }
    }
    return 0;
}

递归降幂

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8543188.html

时间: 2024-12-13 15:06:58

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

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

洛谷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)\)

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

题意 如果对一个数操作\(k\)次,那么这个数会变成\(c^{c^{...^{a_i}}}\),其中\(c\)有\(k\)个. 根据P4139 上帝与集合的正确用法这道题,我们可以知道一个数不断变为自己的欧拉函数,大约\(log\)次就会变成1,而任何数模\(1\)都是\(0\),于是我们可以用势能线段树解决. 因为模数不变,因此我们可以预处理所有\(\varphi(\varphi(...\varphi(p)...))\),之后在线段树上记录操作次数. 这样是三个\(log\)的,因为还要快速幂

[luogu] P3745 [六省联考2017]期末考试 (贪心)

P3745 [六省联考2017]期末考试 题目描述 有 \(n\) 位同学,每位同学都参加了全部的 \(m\) 门课程的期末考试,都在焦急的等待成绩的公布. 第 \(i\) 位同学希望在第 \(t_i\)? 天或之前得知所有课程的成绩.如果在第 \(t_i\) 天,有至少一门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产生 \(C\) 不愉快度. 对于第 \(i\) 门课程,按照原本的计划,会在第 \(b_i\)? 天公布成绩. 有如下两种操作可以调整公布成绩的时间:

P3746 [六省联考2017]组合数问题

P3746 [六省联考2017]组合数问题 \(dp_{i,j}\)表示前\(i\)个物品,取的物品模\(k\)等于\(r\),则\(dp_{i,j}=dp_{i-1,(j-1+k)%k}+dp_{i-1,j}\) \(dp_{i,0},dp_{i,1},dp_{i,2}.....dp_{i,k-1}\) \(\Longrightarrow\) \(dp_{i+1,0},dp_{i+1,1},dp_{i+1,2}.....dp_{i+1,k-1}\) 仔细想想,你能构造出矩阵的 #include

bzoj千题计划265:bzoj4873: [六省联考2017]寿司餐厅

http://www.lydsy.com/JudgeOnline/problem.php?id=4873 选a必选b,a依赖于b 最大权闭合子图模型 构图: 1.源点 向 正美味度区间 连 流量为 美味度 的边 2.负美味度区间 向 汇点 连 流量为 美味度的绝对值 的边 3.区间[i,j] 向 区间[i+1,j].区间[i,j-1] 连 流量为 inf 的边 4.区间[i,i] 向 寿司i 连 流量为 inf 的边 5.寿司i 向 汇点 连 流量为 寿司代号 的边 6.寿司i 向 它的代号 连

bzoj千题计划266:bzoj4872: [六省联考2017]分手是祝愿

http://www.lydsy.com/JudgeOnline/problem.php?id=4872 一种最优解是 从大到小灯有亮的就灭掉 最优解是唯一的,且关灯的顺序没有影响 最优解 对每个开关至多操作1次,(连带着的灯的亮灭改变不算) 设最优解 需要操作cnt次,那么就有cnt盏灯是正确的选择 设 f[i] 表示 有i种正确的选择  变为 有i-1种正确的选择 的 期望次数 那么在n盏灯中,有i盏灯操作1次 就可以 减少一次正确选择 有n-i盏灯是错误的选择,选了它还要把它还原,还原它也