Description

支持以下两个操作:

  • 将第 \(l\) 个数到第 \(r\) 个数 \(a_l,a_{l+1},\dots a_r\) 中的每个数 \(a_i\) 替换为 \(c^{a_i}\)。 \(c\) 是给定的常数。
  • 求第 \(l\) 个数到第 \(r\) 个数的和,对 \(p\) 取模。

\(N\leq 50000,p\leq 10^8\)

Solution

首先有一道这题的弱化版:计算\(2^{2^{2^{\dots}}}\%p\) 的值。

扩展欧拉定理的板子。$$a^b\equiv \begin{cases}a^{b% \phi(p)};;;\qquad gcd(a,p)=1\a^b\qquad;\qquad;; gcd(a,p)\ne1,b<\phi(p)\a^{b%\phi(p)+\phi(p)}\quad gcd(a,p)\ne1,b\geq\phi(p)\end{cases} \qquad (mod;p)$$

首先一个结论是一个数循环取 \(phi\) ,\(O(log)\) 次之后就会变成 \(1\)。证明大概是奇数变偶数,偶数除以二。

所以这个简单题就可以不断的取 \(phi\),当模数变成 \(1\) 时再递归回来就行了。

然后看这道省选题。

最开始还以为 \(c\) 是每次操作给的数,一直在纠结为啥操作 \(O(log)\) 次就不变了。。。

这题难点就是在每次暴力求的时候要注意很多细节。

一个就是快速幂完了之后不知道指数到底该不该再加上一个 \(\phi(p)\)。这个可以在快速幂的过程中判断,具体就是搞一个全区变量 \(flag\),如果当前 \(ans*a\ge p\) 的话,就把这个 \(flag\) 记为 \(1\)。然后返回之后判一下,如果 \(flag\) 是 \(1\) 就加上一个 \(\phi(p)\)。

然而这样是三个 \(log\) 的,不是很过得去。我们需要消掉一个 \(log\)。

这三个 \(log\) 分别是 线段树 \(1\) 个 \(log\),每个数暴力求 \(1\) 个 \(log\),快速幂 \(1\) 个 \(log\)。

前面两个好像都不能优化,考虑把快速幂这个优化掉。

因为 \(p\) 最大是 \(10^8=10^4\times 10^4\),考虑分段打表。

每次求一个数\(a^b\)的时候把 \(b\) 拆成 \(b/10000*10000+b\%10000\),提前打出来 \(a^1,a^2\dots a^{10000}\) 和 \(a^{10000},a^{20000}\dots a^{10^8}\)这么多数。然后快速幂的时候直接查表就好了。

Code

// luogu-judger-enable-o2
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
using std::vector;
const int N=50005;
typedef double db;
#define re register
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)
#define ls cur<<1
#define rs cur<<1|1
#define lss ls,l,mid,ql,qr
#define rss rs,mid+1,r,ql,qr int n,m,p,c;
int phi[N],pos,flag;
pii d[40][10005],e[40][10005];
int val[N],sum[N<<2],tag[N<<2]; int getint(){
int X=0,w=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;else return X;
} void pushup(int cur){
sum[cur]=(sum[ls]+sum[rs])%phi[0];
tag[cur]=min(tag[ls],tag[rs]);
} void build(int cur,int l,int r){
if(l==r){sum[cur]=val[l]%phi[0];return;}int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);pushup(cur);
} int Phi(re int x){
int sq=sqrt(x),now=x;
for(int i=2;i<=x and i<=sq;i++){
if(x%i==0){
now=now/i*(i-1);
while(x%i==0) x/=i;
}
} if(x>1) now=now/x*(x-1);
return now;
} int ksm(int a,int b,int mod){
re int ans=1;int bbb=0;
while(b){
if(b&1){
if((ll)ans*a>=(ll)mod or bbb) flag=1;
ans=(ll)ans*a%mod;
}
if((ll)a*a>=(ll)mod) bbb=1;
a=(ll)a*a%mod;b>>=1;
} if(ans>=mod) flag=1;
return ans%mod;
} int calc(int x,int y){
re int now=x;
if(now>phi[y]) now=now%phi[y]+phi[y];
for(re int i=y;i;i--){
flag=0;int las=now;
now=(ll)e[i-1][now/10000].first*d[i-1][now%10000].first%phi[i-1];
flag=(e[i-1][las/10000].second)|(d[i-1][las%10000].second);
if(flag and i!=1) now+=phi[i-1],flag=0;
}
return now%phi[0];
} void modify(int cur,int l,int r,int ql,int qr){
if(tag[cur]>=pos) return;
if(l==r){
++tag[cur];
sum[cur]=calc(val[l],tag[cur]);
return;
} int mid=l+r>>1;
if(ql<=mid) modify(lss);
if(mid<qr) modify(rss);
pushup(cur);
} int query(int cur,int l,int r,int ql,int qr){
if(ql<=l and r<=qr) return sum[cur];
int mid=l+r>>1,ans=0;
if(ql<=mid) (ans+=query(lss))%=phi[0];
if(mid<qr) (ans+=query(rss))%=phi[0];
return ans;
} signed main(){
n=getint(),m=getint(),p=getint(),c=getint();
phi[0]=p;while(p!=1) phi[++pos]=Phi(p),p=phi[pos];phi[++pos]=1;
for(int i=0;i<10000;i++){
for(int j=0;j<=pos;j++){
flag=0;
d[j][i].first=ksm(c,i,phi[j]);d[j][i].second=flag;
}
}
for(int i=0;i<=10000;i++){
for(int j=0;j<=pos;j++){
flag=0;
e[j][i].first=ksm(c,i*10000,phi[j]);e[j][i].second=flag;
}
}
for(re int i=1;i<=n;i++) val[i]=getint();
build(1,1,n);
while(m--){
if(getint()==0){
int l=getint(),r=getint();
modify(1,1,n,l,r);
} else{
int l=getint(),r=getint();
printf("%d\n",query(1,1,n,l,r)%phi[0]);
}
} return 0;
}

[HEOI2017] 相逢是问候的更多相关文章

  1. BZOJ:4869: [Shoi2017]相逢是问候

    4869: [Shoi2017]相逢是问候 先说点正经的…… 显然做了有限次(我只知道是有限次,而且不会大,别人说是log次?)修改以后会达到不动点,即以后怎么修改都不变了. 然后就随便做了.(3个l ...

  2. bzoj 4869: [Shoi2017]相逢是问候 [扩展欧拉定理 线段树]

    4869: [Shoi2017]相逢是问候 题意:一个序列,支持区间\(a_i \leftarrow c^{a_i}\),区间求和.在模p意义下. 类似于开根操作,每次取phi在log次后就不变了. ...

  3. 【BZOJ4869】相逢是问候(线段树,欧拉定理)

    [BZOJ4869]相逢是问候(线段树,欧拉定理) 题面 BZOJ 题解 根据欧拉定理递归计算(类似上帝与集合的正确用法) 所以我们可以用线段树维护区间最少的被更新的多少次 如果超过了\(\varph ...

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

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

  5. 【BZOJ4869】相逢是问候 [线段树][欧拉定理]

    相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description Informatikverbin ...

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

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

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

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

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

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

  9. Bzoj4869: [Shoi2017]相逢是问候

    题面 传送门 Sol 摆定理 \[ a^b\equiv \begin{cases} a^{b\%\phi(p)}~~~~~~~~~~~gcd(a,p)=1\\ a^b~~~~~~~~~~~~~~~~~ ...

随机推荐

  1. Spring 添加属性集中常见方法

    //创建容器,索要对象, package cn.lijun.Test; import org.junit.Test;import org.springframework.context.Applica ...

  2. P1613 跑路(倍增 + floyd)

    https://www.luogu.org/problemnew/show/P1613 思路: 1.读入 2.建图 3.对于每一个点,向距离它 2^k 长度的点连一条长度为 1 的边 4.在新图上跑1 ...

  3. Spring-Data-JPA @Query注解 Sort排序

    当我们使用方法名称很难,达到预期的查询结果,就可以使用@Query进行查询,@Query是一种添加自定义查询的便利方式 (方法名称查询见http://blog.csdn.net/niugang0920 ...

  4. git-创建新项目

    1.一般第一次使用git,需要进行全局设置,如果下次创建新项目或者fork别人的项目,则不需要再进行设置:但是如果想要提交到不同的代码管理网站,则需要再设置,比如现在我的是在gitlab.com上进行 ...

  5. 设计一个BCD码计数器。

    BCD码计数器的定义: 对于机器语言,机器与人不同,为了让人更好的了解机器语言的数据输出,选用4位二进制数据表示十进制里的每位数据,这便是BCD码. 以下便是BCD码与十进制对应的码表 0------ ...

  6. jenkins net编译部署 笔记 tips

    1 忘记密码 的话,C:\Users\quyongshuo.jenkins\config.xml 修改 true 为false 重新启动 可以重新设置用户信息. 2 修改端口 Java -jar je ...

  7. Rocketmq日志收集与logback集成Demo

    官方文档有简洁的例子,这里就做一个简单补充和实践 直接上logback-boot.xml文件 <?xml version="1.0" encoding="UTF-8 ...

  8. Dispatch Queue 内存结构

    Dispatch 源代码版本是libdispatch-84.5.5  会根据这个结构来分析dispatch_queue 对应的代码实现 参考 GCD源码分析3 -- dispatch_queue篇 ...

  9. 天了噜,Java 8 要停止维护了!

    前些天的中兴事件,已经让国人意识到自己核心技术的不足,这次的 JDK 8 对企业停止免费更新更是雪上加霜.. 以下是 Oracle 官网提示的 JDK8 终止更新公告. 原文内容:Oracle wil ...

  10. 14-使用glusterfs做持久化存储

    使用glusterfs做持久化存储 我们复用kubernetes的三台主机做glusterfs存储. 以下步骤参考自:https://www.xf80.com/2017/04/21/kubernete ...