【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 洛谷 题解 显然最终的答案之和最后一个公布成绩的课程相关. 枚举最后一天的日期,那么维护一下前面有多少天可以向后移,后面总共需 ...
随机推荐
- 浅谈防火墙对FTP的影响及故障排除
本文转载自:http://www.cnblogs.com/emanlee/archive/2013/01/07/2849680.html 向作者致敬! TP是常见的基于TCP的网络服务,它使用了两个 ...
- oracle-不完全数据库恢复-被动恢复-ORA-00313/ORA-00366
继上一篇不完全恢复 oracle-不完全数据库恢复-被动恢复-ORA-00313/ORA-00366 场景2:数据库拥有备份,CURRENT状态日志组中所有的在线日志头损坏,在发生日志切换时实例被自动 ...
- xshell 缺少mfc110u.dll
https://www.microsoft.com/zh-CN/download/details.aspx?id=30679 如果 x64 没有反应,就下载 x86 安装试试,
- Python --链接MYSQL数据库与简单操作 含SSH链接
项目是软硬件结合,在缺少设备的情况,需要通过接口来模拟实现与设备的交互,其中就需要通过从数据库读取商品的ID信息 出于安全考虑 现在很多数据库都不允许通过直接访问,大多数是通过SSH SSH : 数 ...
- linux/linux学习笔记-初识linux(mooc)
一.linux简介 linux版本:内核版本和发行版本 linux企业应用: 1.基于linux的企业服务器 2.linux在嵌入式领域应用 android底层Linux : ios底层unix li ...
- 如何将/etc/issue文件中的内容转换为大写后保存至/tmp/issue.out文件中
cat /etc/issue|tr '[:lower:]' [:upper:] >> /tmp/issue.out
- 使用certbot 为nginx或openresty启用https
certbot 使用letsencrypt 生成免费https证书 以下内容网上整理,原文地址 https://segmentfault.com/a/1190000005797776 -------- ...
- GCC 编译参数
-s 这个参数会把符号表从最终的可执行文件中删除.没有符号表,你就不能用gdb调试了,但是程序会更小 -O0 不做任何优化,这是默认的编译选项 -c 只编译不链接,产生.o文件,就是obj文件,不产生 ...
- [转帖]探秘华为(一):华为和H3C(华三)的爱恨情仇史!
探秘华为(一):华为和H3C(华三)的爱恨情仇史! https://baijiahao.baidu.com/s?id=1620703498823290828&wfr=spider&fo ...
- CentOS 7.6 RPM方式安装Oracle19c的过程
1. 下载需要的安装包: 1.1 preinstall http://yum.oracle.com/repo/OracleLinux/OL7/latest/x86_64/getPackage/orac ...