给定一个序列。要求满足区间取 cai ( c 为定值),区间求和(模 p 意义下)。 N≤5∗104
首先看着就像线段树,这种题一般都有一个暴力不会超时的性质。
对这题来说:
首先要知道如下欧拉定理EXT:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define per(i,a,b) for (int i=a; i>=b; i--)
#define debug(x) {cout<<(#x)<<" "<
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1; char ch=getchar();
while (!(ch>='0'&&ch<='9')) {if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+(ch-'0'); ch=getchar();}
return x*f;
}
const int N = 50005;
const int M = 10005;
int n,m,P,c,k=0;
int a[N],p[N];
bool np[M];
int tot=0,prime[M];
int tr[N<<2],aux[N<<2];
inline void Prep() {
rep(i,2,M-1) {
if (!np[i]) prime[++tot]=i;
rep(j,1,tot) {
if (i*prime[j]>=M) break;
np[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
inline 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;
}
inline void pushup(int x) {
tr[x]=(tr[x<<1]+tr[x<<1|1])%P;
aux[x]=min(aux[x<<1],aux[x<<1|1]);
}
inline void Build(int x,int l,int r) {
if (l==r) {
a[l]=read(); tr[x]=a[l]%P; aux[x]=0; return;
}
int mid=(l+r)>>1;
Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
pushup(x);
}
inline int pow(int a,int b,int P,bool &flag) {
int ret=1;
bool big=0;
while (b) {
if (b&1) {flag|=big|((LL)ret*a>=P); ret=(LL)ret*a%P;}
if ((LL)a*a>=P) big=1;
a=(LL)a*a%P; b>>=1;
}
return ret;
}
inline int Calc(int dep,int x) {
int ret=x; if (ret>=p[dep]) ret=ret%p[dep]+p[dep];
while (dep) {
dep--;
bool flag=0;
ret=pow(c,ret,p[dep],flag);
if (flag) ret+=p[dep];
}
return ret%p[dep];
}
inline void modify(int x,int l,int r,int ll,int rr) {
if (l>rr||rreturn ;
if (aux[x]>=k) return;
if (l==r) {
aux[x]++;
tr[x]=Calc(aux[x],a[l]);
return;
}
int mid=(l+r)>>1;
modify(x<<1,l,mid,ll,rr); modify(x<<1|1,mid+1,r,ll,rr);
pushup(x);
}
inline int query(int x,int l,int r,int ll,int rr) {
if (l>rr||rreturn 0;
if (l>=ll&&r<=rr) return tr[x];
int mid=(l+r)>>1;
return (query(x<<1,l,mid,ll,rr)+query(x<<1|1,mid+1,r,ll,rr))%P;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("verbinden.in","r",stdin);
freopen("verbinden.out","w",stdout);
#endif
Prep(); n=read(),m=read(),P=read(),c=read();
p[0]=P; while (p[k]!=1) {++k;p[k]=phi(p[k-1]);} p[++k]=1;
Build(1,1,n);
while (m--) {
int opt=read(),l=read(),r=read();
if (!opt) modify(1,1,n,l,r);
else printf("%d\n",query(1,1,n,l,r));
}
return 0;
}