正题
题目链接:https://www.luogu.org/problemnew/show/P3934
题目大意
长度为nnn的序列aaa
- 1lrw:1\ l\ r\ w:1 l r w:让l∼rl\sim rl∼r这个区间增加www。
- 2lrp:2\ l\ r\ p:2 l r p:求alal+1al+2...%pa_l^{a_{l+1}^{a_{l+2}^{...}}}\% palal+1al+2...%p直到ara_rar
解题思路
根据欧拉定理
ab%p={ab(b<φ(p))ab%φ(p)+φ(p)(b≥φ(p))a^b\%p=\left\{\begin{matrix} a^b(b<\varphi(p)) \\ a^{b\%\varphi(p)+\varphi(p)}(b\geq \varphi(p)) \\ \end{matrix}\right.ab%p={ab(b<φ(p))ab%φ(p)+φ(p)(b≥φ(p))
所以我们可以使用递推求询问,然后因为有两种情况所以我们需要开一个结构体储存值和是否需要+φ(p)+\varphi(p)+φ(p)。然后我们可以发现这样子不断递推下去,最多推到log(p)log(p)log(p)层左右即可退出
也就是φ(φ(φ(φ(φ(φ(...φ(p)))))))\varphi(\varphi(\varphi(\varphi(\varphi(\varphi(...\varphi(p)))))))φ(φ(φ(φ(φ(φ(...φ(p)))))))这样子下去最多log(p)log(p)log(p)层左右φ\varphiφ就为1了,因为任何数%1=0\% 1=0%1=0所以再往后已经没有必要了,所以询问的时间复杂度是log(p)log(p)log(p)层左右就结束了。
修改的话用树状数组维护就可以了。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lobit(x) (x&-x)
#define ll long long
using namespace std;
const ll N=501000,M=20000000;
ll n,cnt,m,t[N],phi[M+100],pr[M+100];
bool v[M+100];
struct node{ll w,flag;node(ll _w=0,ll _flag=0){w=_w;flag=_flag;}
};
void change(ll x,ll z)
{while(x<=n){t[x]+=z;x+=lobit(x);}
}
ll ask(ll x)
{ll sum=0;while(x){sum+=t[x];x-=lobit(x);}return sum;
}
void updata(ll l,ll r,ll x)
{change(l,x);change(r+1,-x);
}
void Get_phi()
{phi[1]=1;for(ll i=2;i<=20000000;i++){if(!v[i]){pr[++cnt]=i;phi[i]=i-1;}for(ll j=1;j<=cnt;j++){ll t=i*pr[j];if(t>20000000) break;v[t]=1;if(i%pr[j]==0){phi[t]=phi[i]*pr[j];break;}phi[t]=phi[i]*(pr[j]-1);}}
}
node power(ll x,ll b,ll p)
{node ans=node(1,0);if(x>=p){x%=p;ans.flag=1;}while(b){if(b&1) ans.w=ans.w*x;if(ans.w>=p){ans.w%=p;ans.flag=1;}x=x*x;b>>=1;if(x>=p){ans.flag=1;x%=p;}}return ans;
}
node solve(ll l,ll r,ll p)
{ll w=ask(l);node ans;if(p==1) return node(0,1);if(w==1) return node(1,0);if(l==r) return w<p?node(w,0):node(w%p,1);ans=solve(l+1,r,phi[p]);if(ans.flag) ans.w+=phi[p];return power(w,ans.w,p);
}
int main()
{Get_phi();scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++){ll w;scanf("%lld",&w);updata(i,i,w);}for(ll i=1;i<=m;i++){ll op,l,r,w;scanf("%lld%lld%lld%lld",&op,&l,&r,&w);if(op==1) updata(l,r,w);else{node ans=solve(l,r,w);printf("%lld\n",ans.w);}}
}