Portal-->bzoj4869

Solution

  这道题的话。。长得就是线段树的样子qwq

  如果做过的话。。可能会联想到bzoj3211(没写博qwq晚点再说吧哈哈。。)

  首先大胆猜一波结论:这题跟3211一样也是修改到了一定程度就不会再有变化了!那然后写起来就是线段树暴力修改然后如果整个区间达到了修改上限的话那就不走了

  然而这个上限是啥呢。。

​   

  这里还是要用到扩展欧拉定理

\[a^b\equiv
\begin{cases}
&a^{b\%\varphi(p)} &\gcd(a,p)=1\\
&a^b &\gcd(a,p)\neq1,b<\phi(p)\\
&a^{b\%\varphi(p)+\varphi(p)} &\gcd(a,p)\neq1,b\geq\phi(p)
\end{cases}\pmod p
\]

(然而实际上在这题里面第一条并没有什么用毕竟gcd(a,p)=1​这个限制有点令人难受qwq)

  然后接着我们来看一下这个修改操作

  经过多次修改之后应该是长成一堆\(c\)指数翻上去,然后最后那个指数是\(c^a_i\)这个样子(有没有长得很像上帝和集合(bzoj3884)那道题的那一堆\(2\)?)

  然后我们就用类似bzoj3884中的处理方法,大力降幂,跟那题一样,当\(\varphi(p)\)降到\(1\)了之后\(b%\varphi(1)+\varphi(1)=1\),也就是说接下来无论再怎么搞都不会再变了(每个数最多被修改\(log\)次就不会再变了,具体为啥的话在bzoj3884里面有写就不提了)

  与那题不同的是,这里需要判断指数与模数的大小关系来判断能否降成\(b\% \varphi(p)+\varphi(p)\)

​   

  然而这题写起来其实。。有点恶心

  具体一点的话就是:

  首先我们预处理出\(p\)被取\(\varphi\)多少次之后会变成\(1\),记这个次数为\(Mx\),并且将中间每一步的结果记录在一个数组里面,方便我们后面求值的时候直接调用作为模数

  然后我们开一棵线段树,对于修改操作,我们在每个区间记录一个\(sum[x]\)和一个\(mn[x]\),前者表示答案,后者表示这个区间中被修改最少的那个位置被修改了多少次

  在修改的时候,如果说当前区间的\(mn[x]>Mx\)那么说明这个区间所有的位置都已经达到上限可以直接跳过不用管了,否则递归进去处理,一直到叶子节点。叶子节点的话,每次修改的时候能直接改的只是这个节点的\(mn[x]\),而单点的\(sum[x]\)则要重新再算一次

  至于怎么计算\(sum[x]\)的话,可以考虑从降幂的最后一层层推回来,然而因为每次我们推出来的都是下一层的指数部分,如果用最暴力的快速幂求解的话,加上层数最多是\(log\)以及线段树的一个\(log\),总的复杂度会变成\(O(nlog^3n)\),在TLE的边缘试探。。

​  

  然后我们注意到每次快速幂底数其实都是\(c\),所以我们可以考虑将\(c\)的一些次方预处理出来,这样就可以直接调用了

  然而这里有一个小问题,次方数。。最大可以去到\(10^8\),所以这里要用一个小trick:

  我们预处理出\(c\)的\(1-10000\)次方以及\(c^{10000}\)的\(1-10000\)次方,这样对于一个指数,大于\(10^4\)的部分和小于\(10^4\)的部分分开来调用就好了,然后就可以十分愉快地省掉一个\(log\),\(O(nlog^2n)\)相对来说就优秀很多啦

  

​  此外还有一个比较麻烦的地方是,我们需要判断指数和\(p\)的大小,注意,这里的指数是不能取模的,那就有点糟糕了qwq

  这里的解决方案是,注意到由于我们是倒过来推的,这里的指数在用扩展欧拉定理降幂之后会变成\(c\)的若干次方,所以我们可以先预处理出\(c\)的若干次方的值(处理到这个值\(>10^9\)就可以了,也可以更加小一点,反正\(>10^8\)就行),对于\(>10^8\)的部分我们直接打上一个\(tag\)(代码里面我是直接将表示当前幂指数的那个变量赋成\(-1\)),然后根据是否有\(tag\)判断是否能够用扩展欧拉定理的第三条就好了

  

  细节什么的比较。。嗯qwq(调试调了不知道多久最后终于调出来了发现是判断的时候下标忘记+1也是很开心。。。)

​  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=50010,SEG=MAXN*4;
int mod[MAXN],prime[MAXN];
int pwc[10010][30],pwc1[10010][30],pc[60];
bool vis[MAXN];
int n,m,P,c,Mx,Up=10000,ans;
int a[MAXN];
namespace Seg{/*{{{*/
int ch[SEG][2],sum[SEG],mi[SEG];
int n,tot;
void pushup(int x){
sum[x]=(1LL*sum[ch[x][0]]+sum[ch[x][1]])%P;
mi[x]=min(mi[ch[x][0]],mi[ch[x][1]]);
}
void _build(int x,int l,int r){
sum[x]=0; mi[x]=0;
if (l==r) {sum[x]=a[l];return;}
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
pushup(x);
}
void build(int _n){n=_n;tot=1;_build(1,1,n);}
int powc(int Pw,int Mod){return 1LL*pwc1[Pw/Up][Mod]*pwc[Pw%Up][Mod]%mod[Mod];}
int calc(int loc,int Pw){
int nowmi=a[loc],ret=a[loc];
for (int i=Pw-1;i>=0;--i){
if (nowmi==-1||nowmi>=mod[i+1]){
ret=powc(ret%mod[i+1]+mod[i+1],i);
nowmi=-1;
}
else{
ret=powc(ret,i);
if (nowmi<60) nowmi=pc[nowmi];
else nowmi=-1;
}
}
return ret;
}
void _update(int x,int l,int r,int lx,int rx){
if (mi[x]>=Mx) return;
if (lx==rx){
++mi[x];
sum[x]=calc(lx,mi[x]);
return;
}
int mid=lx+rx>>1;
if (l<=mid) _update(ch[x][0],l,r,lx,mid);
if (r>mid) _update(ch[x][1],l,r,mid+1,rx);
pushup(x);
}
void update(int l,int r){_update(1,l,r,1,n);}
int _query(int x,int l,int r,int lx,int rx){
if (l<=lx&&rx<=r) return sum[x];
int mid=lx+rx>>1,ret=0;
if (l<=mid) ret=(1LL*ret+_query(ch[x][0],l,r,lx,mid))%P;
if (r>mid) ret=(1LL*ret+_query(ch[x][1],l,r,mid+1,rx))%P;
return ret;
}
int query(int l,int r){return _query(1,l,r,1,n);}
}/*}}}*/
void prework(int n);
int phi(int x);
int ksm(int x,int y,int p); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int op,l,r;
scanf("%d%d%d%d",&n,&m,&P,&c);
for (int i=1;i<=n;++i) scanf("%d",a+i);
prework(MAXN);
Seg::build(n);
for (int i=1;i<=m;++i){
scanf("%d%d%d",&op,&l,&r);
if (op==0)
Seg::update(l,r);
else{
ans=Seg::query(l,r);
printf("%d\n",ans);
}
}
} void prework(int n){
int cnt=0;
for (int i=2;i<n;++i){
if (!vis[i])
prime[++cnt]=i;
for (int j=1;j<=cnt&&prime[j]*i<n;++j){
vis[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
mod[0]=P;Mx=0;
while (mod[Mx]!=1) ++Mx,mod[Mx]=phi(mod[Mx-1]);
mod[++Mx]=1; for (int i=0;i<=Up;++i)
for (int j=0;j<=Mx;++j)
pwc[i][j]=ksm(c,i,mod[j]);
for (int i=0;i<=Up;++i)
for (int j=0;j<=Mx;++j)
pwc1[i][j]=ksm(ksm(c,Up,mod[j]),i,mod[j]);
//...?
pc[0]=1;
int flag=100000;
for (int i=1;i<60;++i){
if (pc[i-1]==-1) pc[i]=-1;
if (1LL*pc[i-1]*c<=1000000000)
pc[i]=pc[i-1]*c;
else
pc[i]=-1,flag=min(flag,i);
}
} int phi(int x){
int ret=x;
for (int i=1;prime[i]*prime[i]<=x;++i){
if (x%prime[i]) continue;
ret=ret-ret/prime[i];
while (x%prime[i]==0) x/=prime[i];
}
if (x>1) ret=ret-ret/x;
return ret;
} int ksm(int x,int y,int p){
int ret=1,base=x;
for (;y;y>>=1,base=1LL*base*base%p)
if (y&1) ret=1LL*ret*base%p;
return ret;
}

【bzoj4869】相逢是问候的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  10. BZOJ4869 [Shoi2017]相逢是问候 【扩展欧拉定理 + 线段树】

    题目链接 BZOJ4869 题解 这题调得我怀疑人生,,结果就是因为某些地方\(sb\)地忘了取模 前置题目:BZOJ3884 扩展欧拉定理: \[c^a \equiv c^{a \mod \varp ...

随机推荐

  1. Qt-QML-电子罗盘

    使用QML中的Canvas实现电子罗盘绘制,效果图如下 一个简单的电子罗盘,红色N极.其中中间飞机表示当前的指向, 还是比较简单的,直接上代码吧 /* 作者:张建伟 时间:2018年4月27日 简述: ...

  2. CF刷题-Codeforces Round #481-D. Almost Arithmetic Progression

    题目链接:https://codeforces.com/contest/978/problem/D 题解: 题目的大意就是:这组序列能否组成等差数列?一旦构成等差数列,等差数列的公差必定确定,而且,对 ...

  3. 【BUG】12小时制和24小时制获取当天零点问题

    [BUG]12小时制和24小时制获取当天零点问题 最近在写定时服务的时候,要获取当天的零点这个时间,但是是这样获取的 DateTime dt = DateTime.Parse(DateTime.Now ...

  4. Scrum立会报告+燃尽图(十月二十日总第十一次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2246 项目地址:https://git.coding.net/zhang ...

  5. Saver 保存与读取

    tensorflow 框架下的Saver 功能,用以保存和读取运算数据 Saver 保存数据 代码 import tensorflow as tf # Save to file #remember t ...

  6. 2018软工实践—Alpha冲刺(6)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试服务器并行能力 学习MSI.CUDA ...

  7. timestamp 学习

    该答案摘抄自CSDN. 哇,奇迹,跨度三年了,不知道楼主是否已经解决了此问题. 路过,简单说一下,timestamp 主要是记录该行的最后修改时间戳, 注意,这个时间戳是不可以转换为时间的,只能标注该 ...

  8. ORACLE公司传奇历史

    ORACLE公司传奇 ORACLE公司之起源 很难想象,ORACLE 公司的这一段传奇居然要从 IBM 公司开始. 1970年的6月,IBM 公司的研究员埃德加·考特 (Edgar Frank Cod ...

  9. Apache 的知识点

    apache 的官方文档 http://httpd.apache.org/docs/ Mac下如何查看Apache的版本 在终端(Terminal)中输入 apachectl -v,之后回车,结果如下 ...

  10. (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】

    原文地址:http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html 原文作者:豆浆油条 - melon 本文示例代码测试环境是W ...