题意

https://loj.ac/problem/2142

思路

一个数如果要作为指数,那么它不能直接对模数取模,这是常识;

诸如 \(c^{c^{c^{c..}}}\) 的函数递增飞快,不是高精度可以描述的,这也是常识。

所以,此题要用到很多数论知识。

欧拉函数

定义

\(\varphi(n)\) 为 \([1,n]\) 中与 \(n\) 互质的正整数个数(包括 \(1\))。

通式

\(\displaystyle \varphi(n)=n\prod_{p|n}(1-{1\over p})\) 其中 \(p\) 为 \(x\) 的质因子。

如何理解这个式子呢?可以粗略这样理解:\(\displaystyle (1-{1\over p})\) 意思就是筛掉所有能被 \(p\) 整除的数,当然这种理解方法是错误的,只能算是感性理解,方便记忆。

前几项

摘自维基百科:

性质

几条比较重要的性质:

若 \(\gcd(m,n)=1\),有 \(\varphi(mn)=\varphi(m)\varphi(n)\)

令 \(m=2\),不难得出当 \(n\) 为奇数时,\(\varphi(2n)=\varphi(n)\)

另外,对于质数 \(p\),有 \(\varphi(p)=p-1\)

欧拉定理

\(a^{\varphi(n)} \equiv 1 \pmod n\) 其中 \(\gcd(a,n)=1\)

\(n\) 为质数的情况就是著名的费马小定理

扩展欧拉定理

\[a^b=\begin{cases}
a^b\quad \quad \quad \quad\quad \quad \ \ b<\varphi(p)\\
a^{b\mod\varphi(p)+\varphi(p)}\quad b\geq \varphi(p)
\end{cases}\pmod p
\]

扩展欧拉定理把幂的层数和模数都降了下来,用它就可以解决本题了。

回归本题

先考虑暴力做法再尝试优化。我们可以给每个数一个标记,表示多少层 \(c\) 上才是 \(a_i\)。然后每次只需计算这个 \(c^{c^{c^{...^{a_i}}}}\) 即可。

套用扩展欧拉定理,假设标记为 \(3\),就是计算\(c^{c^{c^{a_i}}} \mod p\) 的值。

分两类讨论,当 \(c^{c^{a_i}}<\varphi(p)\),问题就转化成了求 \(c^{c^{a_i}}\mod \varphi(p)\) 的值;否则,只需在此基础上加 \(\varphi(p)\) 即可,而判断大小只需在快速幂上传一个标记就行了。

一路递归下去,当模数变成 \(1\) 时直接返回 \(0\) 即可。

考虑优化。由于模数给定,那么变化显然是从 \(p\) 到 \(\varphi(p)\) 再到 \(\varphi(\varphi(p))\) 这样一路变化的。变化不会超过 \(\log p\) 层,那么总标记次数就不超过 \(n\log p\) 次。

可以用线段树维护一个区间,那么再修改一个区间时,也维护一个区间的最小修改次数的最大值,当它对应的模数已经是 \(1\) 时,便不进行修改。再修改时,要算出 \(c^{c^{c^{...^{a_i}}}}\) 的值,最多修改 \(n\log n\) 次,最深又有 \(\log\) 层,算快速幂又有一个 \(\log\)。三个 \(\log\) 是过不了本题的。

然而快速幂可以直接分块预处理,由于模数不超过 \(\log n\) 个,则分别预处理

\(c^{i} \mod p_k,c^{50000i} \mod p_k\) 的值,以及和 \(p_k\) 的大小关系即可。复杂度降至两个 \(\log\)

查询直接区间求和,一个 \(\log\)。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=5e4+5;
const int _N=5e4;
int P[105],a[N],tot,n,m,c;
LL PW[2][N][105];bool FL[2][N][105];
//PW[i][j][k] c^(i*_N+j)%P[k]
//FL[i][j][k] [c^(i*_N+j)>=P[k]]
LL phi(LL n)
{
LL res=n;
for(LL i=2;i*i<=n;i++)if(n%i==0)
{
res=res/i*(i-1);
while(n%i==0)n/=i;
}
if(n>1)res=res/n*(n-1);
return res;
}
struct node
{
int Mi,sum;
node operator +(const node &_)const
{
return (node){min(Mi,_.Mi),(sum+_.sum)%P[0]};
}
}nd[N<<2];
void build(int k,int l,int r,int *arr)
{
if(l==r)
{
nd[k].Mi=0;
nd[k].sum=arr[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid,arr);
build(k<<1|1,mid+1,r,arr);
nd[k]=nd[k<<1]+nd[k<<1|1];
}
LL Pow(LL p,int id,bool &flag)//c^p%P[id] flag=[c^p>=P[id]]
{
flag=FL[0][p%_N][id]||FL[1][p/_N][id]||(PW[0][p%_N][id]*PW[1][p/_N][id]>=P[id]);
return PW[0][p%_N][id]*PW[1][p/_N][id]%P[id];
}
LL calc(int x,LL y)
{
if(y>=P[x])y=y%P[x]+P[x];
DOR(i,x,1)
{
bool flag;
y=Pow(y,i-1,flag);
if(flag)y+=P[i-1];
}
return y%P[0];
}
void update(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R&&nd[k].Mi>=tot)return;
if(l==r)
{
nd[k].sum=calc(++nd[k].Mi,a[l]);
return;
}
int mid=(l+r)>>1;
if(L<=mid)update(k<<1,L,R,l,mid);
if(R>mid)update(k<<1|1,L,R,mid+1,r);
nd[k]=nd[k<<1]+nd[k<<1|1];
}
int query(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R)return nd[k].sum;
int mid=(l+r)>>1;
if(R<=mid)return query(k<<1,L,R,l,mid);
else if(L>mid)return query(k<<1|1,L,R,mid+1,r);
else return (query(k<<1,L,R,l,mid)+query(k<<1|1,L,R,mid+1,r))%P[0];
}
void pre_compute()
{
FOR(i,0,tot)
{
PW[0][0][i]=1,FL[0][0][i]=(1>=P[i]);
FOR(j,1,_N)
{
PW[0][j][i]=PW[0][j-1][i]*c;
FL[0][j][i]=FL[0][j-1][i]|(PW[0][j][i]>=P[i]);
if(PW[0][j][i]>=P[i])PW[0][j][i]%=P[i];
} PW[1][0][i]=1,FL[1][0][i]=(1>=P[i]);
FOR(j,1,_N)
{
PW[1][j][i]=PW[1][j-1][i]*PW[0][_N][i];
FL[1][j][i]=FL[1][j-1][i]|(PW[1][j][i]>=P[i]);
if(PW[1][j][i]>=P[i])PW[1][j][i]%=P[i];
}
}
} int main()
{
scanf("%d%d%d%d",&n,&m,&P[tot=0],&c);
FOR(i,1,n)scanf("%d",&a[i]);
while(P[tot]!=1)
{
P[tot+1]=phi(P[tot]);
tot++;
}
P[++tot]=1;
pre_compute();
build(1,1,n,a);
while(m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==0)update(1,l,r,1,n);
else printf("%d\n",query(1,l,r,1,n));
}
return 0;
}

SHOI 2017 相逢是问候(扩展欧拉定理+线段树)的更多相关文章

  1. bzoj 4869: [Shoi2017]相逢是问候 [扩展欧拉定理 线段树]

    4869: [Shoi2017]相逢是问候 题意:一个序列,支持区间\(a_i \leftarrow c^{a_i}\),区间求和.在模p意义下. 类似于开根操作,每次取phi在log次后就不变了. ...

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

    题目链接 BZOJ4869 题解 这题调得我怀疑人生,,结果就是因为某些地方\(sb\)地忘了取模 前置题目:BZOJ3884 扩展欧拉定理: \[c^a \equiv c^{a \mod \varp ...

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

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

  4. 洛谷 P3747 [六省联考2017]相逢是问候 解题报告

    P3747 [六省联考2017]相逢是问候 题目描述 \(\text {Informatik verbindet dich und mich.}\) 信息将你我连结. \(B\) 君希望以维护一个长度 ...

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

    4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1313  Solved: 471[Submit][Stat ...

  6. [LNOI] 相逢是问候 || 扩展欧拉函数+线段树

    原题为2017六省联考的D1T3 给出一个序列,m次操作,模数p和参数c 操作分为两种: 1.将[l,r]区间内的每个数x变为\(c^x\) 2.求[l,r]区间内数的和%p 首先,我们要了解一些数论 ...

  7. P3747 相逢是问候 欧拉定理+线段树

    巨难!!! 去年六省联考唯一的一道黑牌题,我今天一天从早到晚,把它从暴力15分怼到了90分,极端接近正解了. bzoj上A了,但是洛谷和loj上面就不行.伪正解会T,奇奇怪怪的类正解会WA.. 那么, ...

  8. BZOJ4869 六省联考2017相逢是问候(线段树+欧拉函数)

    由扩展欧拉定理,a^(a^(a^(……^x)))%p中x作为指数的模数应该是φ(φ(φ(φ(……p)))),而p取log次φ就会变为1,也即每个位置一旦被修改一定次数后就会变为定值.线段树维护区间剩余 ...

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

    传送门 题解 扩展欧拉定理. 线段树维护,已经全改到底了的节点就不管,不然暴力修改下去. //Achen #include<algorithm> #include<iostream& ...

随机推荐

  1. loadRunner手动关联,通过 web_reg_save_param()函数

    Action() { //<B>sign up now</B></A>      /*     web_reg_save_param_regexp(         ...

  2. JustOj 2042: Dada的游戏

    题目描述 Dada无聊时,喜欢做一个游戏,将很多钱分成若干堆排成一列,每堆钱数不固定,谁能找出每堆钱数严格递增的最长区间,谁就是人生赢家了.Dada可能脑子里的水还没干,她找不出来,你来帮她找找吧. ...

  3. <转>jmeter(十二)关联之正则表达式提取器

    本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...

  4. 使用 ffmpeg 转换视频格式

    ffmpeg 是 *nix 系统下最流行的音视频处理库,功能强大,并且提供了丰富的终端命令,实是日常视频处理的一大利器! 实例 flac 格式转 mp3 音频格式转换非常简单: ffmpeg -i i ...

  5. oj练习

    1.toj  1138.   Binomial Showdown   $$ 二项式定理恒等式变换.数据类型溢出(乘法.加法).排列组合数计算优化(C(k,n) = C(n-k,n).排列组合数的计算. ...

  6. Java精选面试题之Spring Boot 三十三问

    Spring Boot Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一: Spring Boot.Spring MVC 和 ...

  7. python的类和对象

    一.面向对象和面向过程 1.1面向过程的特点 优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可. 缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身. 1.2面 ...

  8. shell 获取随机字符串

    一直使用 /dev/urandom 和md5sum的方式去随机字符串,感觉还是不够随机,毕竟只有小写字母和数字嘛. 换换口味: [root@localhost ~]# arr=(`echo {a..z ...

  9. wait与sleep的区别

    1.这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类. sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还 ...

  10. Linux 流量监控工具 iftop

    Linux 流量监控工具 iftop Iftop工具主要用来显示本机网络流量情况及各相互通信的流量集合,如单独同哪台机器间的流量大小,非常适合于代理服务器和iptables服务器使用,这样可以方便的查 ...