题意

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. jQuery事件--keypress([[data],fn])和trigger(type,[data])

    keypress([[data],fn]) 概述 当键盘或按钮被按下时,发生 keypress 事件 keypress 事件与 keydown 事件类似.当按钮被按下时,会发生该事件.它发生在当前获得 ...

  2. 1、第一个android APP

    https://blog.csdn.net/tongyong128/article/details/68484726

  3. js中时间戳转换成时间格式

    js中时间戳转换成时间格式, // 时间戳转换成时间格式 var formatDate = function(date){ date = new Date(date); var y=date.getF ...

  4. Qt介绍1---QPA(Qt Platform Abstraction)

    Qt是一个夸平台的库(一直宣称“Qt everywhere”),但是Qt底层不是夸平台的.比如:Qt中Gui部件的核心类QWidget,该类除了qwidget.h 和 qwidget.cpp两个原文件 ...

  5. 前端框架VUE----cli脚手架(框架)

    一.创建vue项目 npm install vue-cli -g #-g全局 (sudo)npm install vue-cli -g #mac笔记本 vue-init webpack myvue # ...

  6. Java程序员秋招面经大合集(BAT美团网易小米华为中兴等)

    Cvte提前批 阿里内推 便利蜂内推 小米内推 金山wps内推 多益网络 拼多多学霸批 搜狗校招 涂鸦移动 中国电信it研发中心 中兴 华为 苏宁内推 美团内推 百度 腾讯 招商银行信用卡 招银网络科 ...

  7. 使用Holer远程桌面登录家里电脑和公司内网电脑

    1. Holer工具简介 Holer exposes local servers behind NATs and firewalls to the public internet over secur ...

  8. redis 的数据结构

    Redis 数据类型 详解见: http://www.runoob.com/redis/redis-strings.html Redis支持五种数据类型:string(字符串),hash(哈希),li ...

  9. 【新架构测试】Fiddler转发数据测试

    跨域转发设置: 首先进行设置, AutoResponder--> 选中Enable rules和Unmatched requests passthrough 然后Import...导入fiddl ...

  10. oracle /*+ SYS_DL_CURSOR */ 这个hint

    之前一直都没使用过 /*+ SYS_DL_CURSOR */这个提示,今天下午在排查一个性能问题的时候,发现出问题的session在执行一个带了SYS_DL_CURSOR提示的语句,类似于: 经查这个 ...