【LuoguP3747】[六省联考2017] 相逢是问候
题意
给定一个长度为 n 的序列 a , 给定一个正整数 c
每次修改操作是把一段区间内的数 \(x_i\) 修改为 \(c^{x_i}\)
询问区间和模 p 的结果
Sol
修改是把一个数变成 \(c^x\) , 我们很容易想到降幂公式 , 这里由于 p 不一定与 c 互质 , 那么我们就使用扩展欧拉公式 , 也就是:
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] 相逢是问候的更多相关文章
- 洛谷 P3747 [六省联考2017]相逢是问候 解题报告
P3747 [六省联考2017]相逢是问候 题目描述 \(\text {Informatik verbindet dich und mich.}\) 信息将你我连结. \(B\) 君希望以维护一个长度 ...
- [BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)
4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1313 Solved: 471[Submit][Stat ...
- 洛谷P3747 [六省联考2017]相逢是问候
传送门 题解 扩展欧拉定理. 线段树维护,已经全改到底了的节点就不管,不然暴力修改下去. //Achen #include<algorithm> #include<iostream& ...
- bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候
http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath&g ...
- BZOJ4869 六省联考2017相逢是问候(线段树+欧拉函数)
由扩展欧拉定理,a^(a^(a^(……^x)))%p中x作为指数的模数应该是φ(φ(φ(φ(……p)))),而p取log次φ就会变为1,也即每个位置一旦被修改一定次数后就会变为定值.线段树维护区间剩余 ...
- P3747 [六省联考2017]相逢是问候
题意 如果对一个数操作\(k\)次,那么这个数会变成\(c^{c^{...^{a_i}}}\),其中\(c\)有\(k\)个. 根据P4139 上帝与集合的正确用法这道题,我们可以知道一个数不断变为自 ...
- 2017 [六省联考] T2 相逢是问候
4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1205 Solved: 409[Submit][Stat ...
- 【BZOJ4873】[六省联考2017]寿司餐厅(网络流)
[BZOJ4873][六省联考2017]寿司餐厅(网络流) 题面 BZOJ 洛谷 题解 很有意思的题目 首先看到答案的计算方法,就很明显的感觉到是一个最大权闭合子图. 然后只需要考虑怎么构图就行了. ...
- 【BZOJ4868】[六省联考2017]期末考试(贪心)
[BZOJ4868][六省联考2017]期末考试(贪心) 题面 BZOJ 洛谷 题解 显然最终的答案之和最后一个公布成绩的课程相关. 枚举最后一天的日期,那么维护一下前面有多少天可以向后移,后面总共需 ...
随机推荐
- centOS7杀死进程命令
查看当前所有正在运行的进程,可以看到80端口被httpd占用了(80端口希望分配给nginx使用,而不是httpd) netstat -tpnul 这里以杀死httpd进程为例: 先查看 httpd ...
- Spring 之 IOC ,DI 理论
本文是依照极客学院java<Spring之IOC>章节学习的心得.随笔记录 浅谈IOC:(Inversion of Control, 控制反转) Spring 核心容器,贯穿始终.所谓IO ...
- cobbler批量安装系统
cobbler是一个可以实现批量安装系统的Linux应用程序.它有别于pxe+kickstart,cobbler可以实现同个服务器批量安装不同操作系统版本. 1.系统环境准备及其下载cobbler 1 ...
- 问题记录 | deepin15.10重装nvidia驱动及cuda
问题描述: nvidia-smi也有显示,显卡驱动是在的,而且nvcc显示出来的cuda版本9.0也没错,不是9.1.不知道问题所在,索性重装全部. sudo tee /proc/acpi/bbswi ...
- Express中间件body-parser
在http请求种,POST.PUT.PATCH三种请求方法中包含着请求体,也就是所谓的request,在Nodejs原生的http模块中,请求体是要基于流的方式来接受和解析. body-parser是 ...
- 小白用Mac
老话说的好,“最近老板发我一个Mac,但是不会用,嘎嘎嘎嘎” 1.安装软件 安装 Homebrew Homebrew:使用 Homebrew 安装 Apple 没有预装但 你需要的东西,尤其是非界面管 ...
- MySQL-快速入门(10)触发器
1.什么是触发器 触发器是与表有关的命名数据库对象.触发器由事件来触发某个操作. 触发器是特殊的存储过程,触发器不需要call语句来调用,也不需要手工启动,只需要确定一个预定义的事件发生的时候,就会被 ...
- (三)认识twisted reactor
一.reactor是单线程模型,简单粗暴,也就是说网络IO和我们的业务逻辑一般是在一个线程里,其中网络IO通过event loop的方式去异步执行,效率也很高.看下官网的这幅图,比较清晰 twiste ...
- P1049装箱问题
这是一道DP(背包)水题. 题目问剩余空间最小,那么意思为装得最多.拿到题后便习惯了用贪心去思考,发现局部并不是全局最优,所以考虑dp.但是发现01背包的价值呢?(这个错误的想法就显示了我对dp理解得 ...
- kotlin学习(10)反射
反射,简单来说,是一种在运行时动态地访问对象属性和方法的方式,而不需要事先确定这些属性是什么. Kotlin反射API:KClass.KCallable.KFunction.KPropperty KC ...