Description
给定长度为n的序列要求资瓷
- 区间加x
- 求 a l a l + 1 a l + 2 . . . ( m o d p ) {a_l} ^{{a_{l+1}}^{a_{l+2}...}}\pmod p alal+1al+2...(modp)
Solution
这种叠起来的柿子看起来就像是拓展欧拉定理
打个表可以发现1e7以内的数字最多连续取log次phi就变成1了
也就是说我们只需要做log次。坑点就是拓展欧拉定理的指数上有一个phi[p],加不加取决于指数和phi[p]的大小关系。这个在特判一下就可以了
Code
#include <stdio.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) (x&-x)
typedef long long LL;
const int M=20000005;
const int N=500005;
LL c[N*2];
int phi[M],prime[M],n;
bool not_prime[M];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void pre_work(int n) {
phi[1]=1;
rep(i,2,n) {
if (!not_prime[i]) {
prime[++prime[0]]=i;
phi[i]=i-1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=n;j++) {
not_prime[i*prime[j]]=1;
if (i%prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
void add(int x,LL v) {
for (;x<=n;x+=lowbit(x)) c[x]+=v;
}
LL get(int x) {
LL res=0;
for (;x;x-=lowbit(x)) res+=c[x];
return res;
}
LL ksm(LL x,LL dep,LL MOD) {
LL res=1; bool lxf=false,wjp=false;
for (;dep;dep>>=1) {
if (dep&1) {
wjp|=lxf;
res=res*x;
if (res>=MOD) {
res%=MOD;
wjp=true;
}
}
if (x>=MOD) x%=MOD,lxf=true;
x=x*x;
if (x>=MOD) x%=MOD,lxf=true;
}
return res+wjp*MOD;
}
LL solve(int l,int r,LL p) {
if (p==1||r<l) return 1;
LL x=get(l),y=solve(l+1,r,phi[p]);
return ksm(x,y,p);
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
pre_work(2e7);
n=read(); int m=read();
rep(i,1,n) {
int x=read();
add(i,x); add(i+1,-x);
}
for (;m--;) {
int opt=read(),l=read(),r=read(); LL x; scanf("%lld",&x);
if (opt==1) add(l,x),add(r+1,-x);
else printf("%lld\n", solve(l,r,x)%x);
}
return 0;
}