bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候
http://www.lydsy.com/JudgeOnline/problem.php?id=4869
欧拉降幂+线段树,每个数最多降log次,模数就会降为1
#include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 50001 int n,m,p,c; int a[N]; int sum[N<<2]; int tag[N<<2]; int lim,pi[101],phi[101]; int ans; bool flag; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } int Pow(int a,int b,int mod) { int res=1; while(b) { if(b&1) { if(1LL*res*a>=mod) flag=true; res=1LL*res*a%mod; } if(1LL*a*a>=mod) flag=true; a=1LL*a*a%mod; b>>=1; } return res; } void build(int k,int l,int r) { if(l==r) { sum[k]=a[l]; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum[k]=(sum[k<<1]+sum[k<<1|1])%p; } int get_phi(int x) { int y=sqrt(x); int ph=x; for(int i=2;i<=y;++i) if(!(x%i)) { while(!(x%i)) x/=i; ph=ph/i*(i-1); } if(x>1) ph=ph/x*(x-1); return ph; } int f(int dep,int x) { int tmp=x; if(tmp>=phi[dep]) tmp=tmp%phi[dep]+phi[dep]; for(int i=dep;i;--i) { flag=false; tmp=Pow(c,tmp,pi[i]); if(flag) tmp+=phi[i-1]; } return tmp; } void change(int k,int l,int r,int opl,int opr) { if(tag[k]>=lim) return; if(l==r) { tag[k]++; sum[k]=f(tag[k],a[l]); return; } int mid=l+r>>1; if(opl<=mid) change(k<<1,l,mid,opl,opr); if(opr>mid) change(k<<1|1,mid+1,r,opl,opr); tag[k]=min(tag[k<<1],tag[k<<1|1]); sum[k]=(sum[k<<1]+sum[k<<1|1])%p; } void query(int k,int l,int r,int opl,int opr) { if(l>=opl && r<=opr) { ans+=sum[k]; ans%=p; return; } int mid=l+r>>1; if(opl<=mid) query(k<<1,l,mid,opl,opr); if(opr>mid) query(k<<1|1,mid+1,r,opl,opr); } int main() { read(n); read(m); read(p); read(c); for(int i=1;i<=n;++i) read(a[i]); build(1,1,n); int tmp=p; while(pi[lim]!=1) { pi[++lim]=tmp; phi[lim]=get_phi(tmp); tmp=phi[lim]; } int ty,l,r; while(m--) { read(ty); read(l); read(r); if(!ty) change(1,1,n,l,r); else { ans=0; query(1,1,n,l,r); printf("%d\n",ans); } } return 0; }