题目链接

题意

给定一个长度为 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. 微博获取原图时重定向到图片的url

    微博获取原图时重定向到图片的url,所以获取的是乱码 jsoup默认是执行重定向的. //根据Url获取页面对应的Document public static Document getDoc1(Str ...

  2. 有关MSSQL2000在Win7上的安装

    https://baijiahao.baidu.com/s?id=1593533837896849226&wfr=spider&for=pc 怎么在win7下安装sql server2 ...

  3. 学用 TStringGrid [6] - Options

    本例运行效果图: 一般修改 TStringGrid 的 Options 直接在设计时选一下 True 或 False 就行了; 代码中可以像下面操作:   StringGrid1.Options := ...

  4. flultter listview异常type '(BuildContext, int) => dynamic' is not a subtype of type '(BuildContext, int) => Widget'

    type '(BuildContext, int) => dynamic' is not a subtype of type '(BuildContext, int) => Widget' ...

  5. Linux下安装Elasticsearch6.5

    1.安装JDK8(Elastic 需要 Java 8 环境) 1)下载jdk8文件:http://www.oracle.com/technetwork/java/javase/downloads/jd ...

  6. 解决Pip install Pillow 失败问题

    当我在使用Django一个上传图片功能的时候, Django 提示我安装 Pillow这个图片处理的库, 当我尝试安装的时候. 总是提示安装失败 报如下错误. v = self._sslobj.rea ...

  7. anaconda3,将python版本回退(python3.7---python3.5)

    2019/6 安装anaconda3时,安装了默认的最新版本,但是由于不能兼容tensorflow,我又配置了一个python3.5的环境: 可惜这里真的不晓得咋回事,在python3.5中进入jup ...

  8. MySql 性能优化之 Explain

    MySQL 之 Explain 输出分析 背景 前面的文章写过 MySQL 的事务和锁,这篇文章我们来聊聊 MySQL 的 Explain,估计大家在工作或者面试中多多少少都会接触过这个.可能工作中实 ...

  9. [DS+Algo] 007 希尔排序及其代码实现

    步骤 将数组列在一个表(一行多列)中,按特定的步长进行插入排序 步长从 length/2 到 1,每次除 2 将数组转换至表是为了更好地理解这算法,算法本身还是使用数组进行排序 算法性能 (根据步长序 ...

  10. P2562kitty猫基因

    这道题是安徽NOI省选题,但是难度并没有那么难. 这道题是一个字符串的递归题,有很多大佬用线段树来写的(我也想学线段树,lowbit当头一棒).题意为全部相同则输出B或A,不同则分成长度相同的两个子串 ...