题目链接

题意

给定一个长度为 n 的序列 a , 给定一个正整数 c

每次修改操作是把一段区间内的数 \(x_i\) 修改为 \(c^{x_i}\)

询问区间和模 p 的结果

Sol

修改是把一个数变成 \(c^x\) , 我们很容易想到降幂公式 , 这里由于 p 不一定与 c 互质 , 那么我们就使用扩展欧拉公式 , 也就是:

\[a^{x}=\begin{cases}
a^{x} \;\;,\;\;x<\varphi(p) \\
a^{x\mod\varphi(p)+\varphi(p)}\;\;,x\geq \varphi(p)\\
\end{cases}\]

\(\varphi(p)\) 函数对于一个数来说 , 做多取 \(O(log_2\ p)\) 次就会变成 1 , 这样我们直接暴力在线段树上修改每一个数 , 直到这个数变成了 \(c^{c^{c^{c^{c^{\dots}}}}}\) , 最后的答案我们可以通过直接使用扩展欧拉定理递归算出 , 这样每一个数也最多被修改 \(log\) 次就不会再变了 , 那么我们总共的单点修改的次数就会是 \(O(nlogn)\) 级别的。

于是我们只需要考虑单点修改。

对于一次单点修改,我们相当于是把原来的数底下塞上一个 c , 由于这一步操作对于每一层模数都变化了, 并不能直接得到, 那么必须每次都要单独算,每次暴力用公式递归进去计算的话复杂度变成了 \(O(nlog^3n)\) 级别的,不能通过所有数据。

考虑优化,我们把快速幂的复杂度优化掉就行了,由于指数的级别最大和 p 差不多,我们对于每一个递归中会遇到模数 \(p\) 处理一个 \(c^x\) 和 \(c^{10000x}\) 就可以 \(O(1)\) 把幂的结果算出来了。

一个比较令人头痛的问题就是判断当前的指数是否大于了当前模数的 欧拉函数值,因为这时我们还要在把指数加上一个 \(\varphi(p)\) ,只需要每次计算的时候先用 \(long\) \(long\) 存好看是否大于模数,用变量记下是否比模数大了就行了。

code:

#include<bits/stdc++.h>
using namespace std;
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
typedef long long ll;
int n,m,p,c;
const int N=5e4+10;
int a[N];
const int MAXN=N<<2;
int hsize[MAXN],dat[MAXN],times[MAXN],sum[MAXN];
#define ls (u<<1)
#define rs (u<<1|1)
int final_ans;
int phi[N],cnt=0;
const int MAXM=2e4;
struct Powerset{
int Mod;bool bom[MAXM];int val[MAXM];
inline void Prepare(int base,int Mo,bool cbom){
Mod=Mo;bom[0]=0;val[0]=1;bom[1]=cbom,val[1]=base;
for(int i=2;i<MAXM;++i) {
ll res=(ll)val[i-1]*base;
bom[i]=bom[i-1];if(res>=Mod) bom[i]=1;
val[i]=res%Mod;
}return;
}
}Po[61][2];
inline int Sum(int x,int y){x+=y;if(x>=p) x-=p;return x;}
inline int Dif(int x,int y){x-=y;if(x< 0) x+=p;return x;}
inline int fpow(int x,int k,int p){int ret=1;for(;k;k>>=1,x=(ll)x*x%p)if(k&1) ret=(ll)ret*x%p;return ret;}
const int INF=2147483647;
void Build(int u,int l,int r){
if(l==r) {dat[u]=a[l],hsize[u]=1,sum[u]=a[l],times[u]=0;return;}
int mid=l+r>>1;
Build(ls,l,mid),Build(rs,mid+1,r);
hsize[u]=r-l+1;sum[u]=Sum(sum[ls],sum[rs]);
}
inline int Get_phi(int x){int ret=x;
for(int i=2;i*i<=x;++i) {if(x%i==0) {ret-=ret/i;x/=i;while(x%i==0)x/=i;}}
if(x>1) ret-=ret/x;return ret;
}
inline int Calc(int p){
if(p==1) return 0;int nowphi=Get_phi(p);
int ret=fpow(c,Calc(nowphi)+nowphi,p)%p;
phi[++cnt]=nowphi;return ret;
}
inline int Fpow(int x,int k,int P){
bool boom=0,boompow=0;int ret=1;
while(k){
if(k&1) {ll res=(ll)ret*x;if(res>=P) boom=1;boom|=boompow;ret=res%P;}
boompow=0;ll res=(ll)x*x;
if(res>=P) boompow=1;x=res%P;k>>=1;
}if(boom) ret+=P;return ret;
}
inline int Solve(int t,int a,int id){
if(!t) return a>phi[id]? (a%phi[id]+phi[id]):a;
int Dat=Solve(t-1,a,id+1);
if(!id) return (ll)Po[id][0].val[Dat%MAXM]*Po[id][1].val[Dat/MAXM]%phi[id];
else {
int r1=Dat%MAXM,r2=Dat/MAXM;
bool bm=Po[id][0].bom[r1]|Po[id][1].bom[r2];
if(bm) return (ll)Po[id][0].val[r1]*Po[id][1].val[r2]%phi[id]+phi[id];
else return (ll)Po[id][0].val[r1]*Po[id][1].val[r2]%phi[id];
}
}
inline void Modify(int u,int l,int r,int L,int R){
if(!hsize[u]) return;
if(l>=L&&r<=R) {
if(l==r) {++times[u];
if(times[u]>cnt) sum[u]=final_ans,hsize[u]=0;
else sum[u]=Solve(times[u],dat[u],0)%p;
return;
}int mid=l+r>>1;
Modify(ls,l,mid,L,R);Modify(rs,mid+1,r,L,R);
sum[u]=Sum(sum[ls],sum[rs]);hsize[u]=hsize[ls]+hsize[rs];
return;
}int mid=l+r>>1;
if(mid>=L) Modify(ls,l,mid,L,R);
if(mid< R) Modify(rs,mid+1,r,L,R);
sum[u]=Sum(sum[ls],sum[rs]);
hsize[u]=hsize[ls]+hsize[rs];
}
inline int Query(int u,int l,int r,int L,int R){
if(l>=L&&r<=R) return sum[u];
int mid=l+r>>1;
if(mid>=R) return Query(ls,l,mid,L,R);if(mid<L) return Query(rs,mid+1,r,L,R);
return Sum(Query(ls,l,mid,L,mid),Query(rs,mid+1,r,mid+1,R));
}
namespace Fun{
bool tag[MAXN];
inline void set1(int u,int l,int r){sum[u]=r-l+1;tag[u]=1;return;}
inline void push_down(int u,int l,int mid,int r){if(!tag[u]) return;set1(ls,l,mid),set1(rs,mid+1,r),tag[u]=0;}
inline void Modify(int u,int l,int r,int L,int R){
if(l>=L&&r<=R) return set1(u,l,r);
int mid=l+r>>1;push_down(u,l,mid,r);
if(mid>=L) Modify(ls,l,mid,L,R);if(mid<R) Modify(rs,mid+1,r,L,R);
sum[u]=Sum(sum[ls],sum[rs]);
}
inline int Query(int u,int l,int r,int L,int R){
if(l>=L&&r<=R) return sum[u];
int mid=l+r>>1;push_down(u,l,mid,r);
if(mid>=R) return Query(ls,l,mid,L,R);if(mid<L) return Query(rs,mid+1,r,L,R);
return Sum(Query(ls,l,mid,L,mid),Query(rs,mid+1,r,mid+1,R));
}
void work(){
for(int i=1;i<=m;++i) {
int op,l,r;init(op),init(l),init(r);
if(op==0) Modify(1,1,n,l,r);
else printf("%d\n",Query(1,1,n,l,r)%p);
}
}
}
inline void Prework(){
for(int i=0;i<cnt;++i) {
Po[i][0].Prepare(c,phi[i],c>=phi[i]);
Po[i][1].Prepare(fpow(c,2e4,phi[i]),phi[i],1);
}return;
}
int main()
{
init(n),init(m),init(p),init(c);
for(int i=1;i<=n;++i) init(a[i]);
Build(1,1,n);
if(c==1) Fun::work();
else {
phi[0]=p;final_ans=Calc(p);
reverse(phi+1,phi+1+cnt);
Prework();
for(int i=1;i<=m;++i) {
int op,l,r;init(op),init(l),init(r);
if(op==0) Modify(1,1,n,l,r);
else printf("%d\n",Query(1,1,n,l,r)%p);
}
}
return 0;
}

【LuoguP3747】[六省联考2017] 相逢是问候的更多相关文章

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

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

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

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

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

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

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath&g ...

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

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

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

    题意 如果对一个数操作\(k\)次,那么这个数会变成\(c^{c^{...^{a_i}}}\),其中\(c\)有\(k\)个. 根据P4139 上帝与集合的正确用法这道题,我们可以知道一个数不断变为自 ...

  7. 2017 [六省联考] T2 相逢是问候

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

  8. 【BZOJ4873】[六省联考2017]寿司餐厅(网络流)

    [BZOJ4873][六省联考2017]寿司餐厅(网络流) 题面 BZOJ 洛谷 题解 很有意思的题目 首先看到答案的计算方法,就很明显的感觉到是一个最大权闭合子图. 然后只需要考虑怎么构图就行了. ...

  9. 【BZOJ4868】[六省联考2017]期末考试(贪心)

    [BZOJ4868][六省联考2017]期末考试(贪心) 题面 BZOJ 洛谷 题解 显然最终的答案之和最后一个公布成绩的课程相关. 枚举最后一天的日期,那么维护一下前面有多少天可以向后移,后面总共需 ...

随机推荐

  1. Vue知识整理16:单文件组件

    过程较为复杂,这里直接写出视频地址,可以直接查看 https://learning.dcloud.io/#/?vid=14

  2. 前端必须掌握的 docker 技能(3)

    概述 作为一个前端,我觉得必须要学会使用 docker 干下面几件事: 部署前端应用 部署 nginx 给部署的 nginx 加上 https 使用 docker compose 进行部署 给 ngi ...

  3. Spring框架中的依赖注入

    依赖注入(DI : Dependency Injection)是基于.xml配置文件内节点的书写. 注入类型: 1.设置注入,调用了Bean的setXXX()进行值注入 普通属性(value值表示要显 ...

  4. Windows命令集锦

    1.用于私网的IP地址段: 10.0.0.0/8: 10.0.0.0-10.255.255.255 172.16.0.0/12: 172.16.0.0-172.31.255.255 192.168.0 ...

  5. 终极Shell - Oh My Zsh

    介绍 zsh: 与 bash 同为 shell 软件,适用于 linux 和 mac,mac 与百度开发机已自带. oh-my-zsh:zsh 的一个开源配置方案,即下即用,免去复杂的配置过程.配置后 ...

  6. 【MM系列】SAP 关于更改物料的价格控制类型

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP 关于更改物料的价格控制类型 ...

  7. 【SQL系列】深入浅出数据仓库中SQL性能优化之Hive篇

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[SQL系列]深入浅出数据仓库中SQL性能优化之 ...

  8. 11.metasploit辅助模块----基本Exp----ARP欺骗中间人MITM----WordPress破解

    metasploit辅助模块 信息收集 auxiliary scanners 使用metasploitable靶机 桥接 同一局域网 msfconsole nmap -sT 靶机IP nmap -sS ...

  9. Command line is too long. Shorten command line for testMLDome1 or also for Application default configuration

    在.idea文件夹中,更改workspace.xml文件 加这段语句: <property name="dynamic.classpath" value="true ...

  10. Golang中的error类型

    Golang中的error类型 error类型本身就是一个预定义好的接口,里面定义了一个method type error interface { Error() string } 生成一个新的err ...