原题为2017六省联考的D1T3

给出一个序列,m次操作,模数p和参数c

操作分为两种:

1、将[l,r]区间内的每个数x变为\(c^x\)

2、求[l,r]区间内数的和%p


首先,我们要了解一些数论姿势:

1、扩展欧拉定理

//我们熟知的费马小定理用于p是质数,欧拉定理用于a,p互质,而这道题都不满足这个限制

当\((b>=\phi(p))\)时,\(a^b=a^{b\mod \phi(p) + \phi(p)}\)

2、(其实不算数论姿势)一个数最多经过log此\(\phi\)就会变成1

所以我们发现,一个数在经过几次变化后,指数永远是\(x\mod1+1\),也就是1,它就再也不变了!

//上面这里不理解的话,可以考虑这样一道题

//给定一个长度为n的序列a,每次询问区间[l,r] \(a_l^{a_{l+1}^{…}}\)的值。\(n<=10^5,m<=10^9\)

//原题应该是叫power tower

所以我们建一棵线段树,维护当前区间和和这个区间中被修改的最小次数。

预处理出对于mod p来讲,几次后一定会不变,记为k。每次修改将当前位置的修改次数++。如果这个区间的最小修改次数>=k,那么就不需要修改了,否则暴力修改。

因为每次的修改次数不一样,所以要用初值a[i]计算times后当前数会变为什么。

因为有n个数,每个数会被暴力修改\(\log(p)\)次,每次修改是\(\log(n)\)的,再乘上快速幂的复杂度\(\log\)就是\(O(nlog^3)\)

这样基本能过了,但是被卡常的话就不稳了。可以考虑预处理c的快速幂,反正c是固定的……

//bzoj不预处理就能过,洛谷过不了(也可能是博主写的比较菜)

贴一份没有预处理的代码

#include<cstdio>
#include<algorithm>
#define N 50010
#define M 10010
typedef long long ll;
using namespace std;
int a[N],n,m,prime[N],tot,p[N],P,c,op,l,r,k,MOD;
bool np[N];
struct hhh
{
int l,r,sum,is;
}tre[4*N]; int read()
{
int ans=0,fu=1;
char j=getchar();
for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
return ans*fu;
} int ksm(int x,int y,int mo,bool &flag)
{
int ret=1;
bool big=0;
while (y)
{
if (y&1)
{
flag|=big|((ll)ret*x>=mo);
ret=(ll)ret*x%mo;
}
if ((ll)x*x>=mo) big=1;
x=(ll)x*x%mo;
y>>=1;
}
return ret;
} void build(int i,int l,int r)
{
tre[i].l=l;tre[i].r=r;tre[i].is=0;
if (l==r)
{
tre[i].sum=a[l]%P;
return ;
}
int mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
tre[i].sum=(tre[i*2].sum+tre[i*2+1].sum)%P;
} int calc(int x,int dep)
{
int ret=x;
if (ret>=p[dep]) ret=ret%p[dep]+p[dep];
while (dep)
{
dep--;
bool flag=0;
ret=ksm(c,ret,p[dep],flag);
if (flag) ret+=p[dep];
}
return ret%P;
} void modify(int i,int l,int r)
{
if (l>tre[i].r || r<tre[i].l) return ;
if (tre[i].is>=k) return ;
if (tre[i].l==tre[i].r)
{
tre[i].is++;
tre[i].sum=calc(a[tre[i].l],tre[i].is);
return ;
}
modify(i*2,l,r);
modify(i*2+1,l,r);
tre[i].sum=(tre[i*2].sum+tre[i*2+1].sum)%P;
tre[i].is=min(tre[i*2].is,tre[i*2+1].is);
} int query(int i,int l,int r)
{
if (l>tre[i].r || r<tre[i].l) return 0;
if (tre[i].l>=l && tre[i].r<=r) return tre[i].sum;
return (query(i*2,l,r)+query(i*2+1,l,r))%P;
} int phi(int n)
{
int res=n,a=n;
for(int i=2; i*i<=a; i++)
if(a%i==0)
{
res=res/i*(i-1);
while (a%i==0) a/=i;
}
if (a>1) res=res/a*(a-1);
return res;
} int main()
{
n=read();m=read();P=read();c=read();
for (int i=1;i<=n;i++) a[i]=read();
p[0]=P;
while (p[k]!=1) { ++k; p[k]=phi(p[k-1]); }
p[++k]=1;
build(1,1,n);
while (m--)
{
op=read();l=read();r=read();
if (op) printf("%d\n",query(1,l,r));
else modify(1,l,r);
}
return 0;
}

[LNOI] 相逢是问候 || 扩展欧拉函数+线段树的更多相关文章

  1. LOJ #2142. 「SHOI2017」相逢是问候(欧拉函数 + 线段树)

    题意 给出一个长度为 \(n\) 的序列 \(\{a_i\}\) 以及一个数 \(p\) ,现在有 \(m\) 次操作,每次操作将 \([l, r]\) 区间内的 \(a_i\) 变成 \(c^{a_ ...

  2. bzoj4869: [Shoi2017]相逢是问候(欧拉函数+线段树)

    这题是六省联考的...据说数据还出了点锅,心疼六省选手QAQ 首先要知道扩展欧拉定理... 可以发现每次区间操作都会使模数进行一次phi操作,而一个数最多取logp次phi就会变成1,这时后面的指数就 ...

  3. LightOJ 1370 Bi-shoe and Phi-shoe 欧拉函数+线段树

    分析:对于每个数,找到欧拉函数值大于它的,且标号最小的,预处理欧拉函数,然后按值建线段树就可以了 #include <iostream> #include <stdio.h> ...

  4. loj1370(欧拉函数+线段树)

    传送门:Bi-shoe and Phi-shoe 题意:给出多个n(1<=n<=1e6),求满足phi(x)>=n的最小的x之和. 分析:先预处理出1~1e6的欧拉函数,然后建立一颗 ...

  5. [BZOJ4026]dC Loves Number Theory 欧拉函数+线段树

    链接 题意:给定长度为 \(n\) 的序列 A,每次求区间 \([l,r]\) 的乘积的欧拉函数 题解 考虑离线怎么搞,将询问按右端点排序,然后按顺序扫这个序列 对于每个 \(A_i\) ,枚举它的质 ...

  6. 【bzoj4869】[Shoi2017]相逢是问候 扩展欧拉定理+并查集+树状数组

    题目描述 Informatik verbindet dich und mich. 信息将你我连结. B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以分为两种:0 ...

  7. BZOJ 4034: [HAOI2015]树上操作 [欧拉序列 线段树]

    题意: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 显然树链剖分可做 ...

  8. BZOJ 4034 树上操作(树的欧拉序列+线段树)

    刷个清新的数据结构题爽一爽? 题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x ...

  9. BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)

    题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...

随机推荐

  1. Ruby 基础教程1-5

    1.条件语句 if unless case        unless和if相反,条件不成立则执行   2.条件  除了 false和nil 其他都是true   3.unless 语法        ...

  2. Windows如何设置动态和静态ip地址

    打开控制面板,一般在电脑的菜单栏能找到,win8和win10可以使用快捷键(win键+X键),找不到的朋友可以搜索一下.   进入到网络和共享中心,点击更改适配器设置.   这里显示的是电脑所以的网络 ...

  3. Linux命令应用大词典-第4章 目录和文件操作

    4.1 pwd:显示(打印)当前工作目录路径 4.2 cd:更改工作目录路径 4.3 ls: 列出目录和文件信息: 4.4 dir:列出目录或文件信息: 4.5 dirs:显示目录列表: 4.6 to ...

  4. 转:vue生命周期流程图

  5. GIT: 分布式开发 代码管理工具使用命令大全

    代码管理工具: GIT     什么是GIT? Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目 Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常 ...

  6. python 终极篇 ---django 认证

    Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Djang ...

  7. Java学习 · 初识 多线程

    多线程 1. 基础概念 a)     程序 Program i.           静态代码,指令集,应用程序执行的蓝本 b)    进程 Process i.           动态概念,正在运 ...

  8. Java三种编译方式

    Java程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代 ...

  9. Centos7下部署activeMQ消息队列服务

    #1.下载activeMQlinux包 http://activemq.apache.org/activemq-5100-release.html   下载linux的activeMQ包 #2.使用X ...

  10. Bootstrap框架(组件)

    按钮组 通过按钮组容器把一组按钮放在同一行里.通过与按钮插件联合使用,可以设置为单选框或多选框的样式和行为. 按钮组中的工具提示和弹出框需要特别的设置 当为 .btn-group 中的元素应用工具提示 ...