I
Informatik verbindet dich und mich
扩展欧拉定理+线段树。
I
由扩展欧拉定理得,cc...最终上面的指数必定变成1.(不会打这个东西。。。)
最多取log次就会变成1,然后就没用了。
我们每次算的时候再快速幂的话时间复杂度是貌似不能过的。好像是nlog^3n
至少我加了N发卡常还是过不了。
但是我们通过题解发现实际上每次快速幂的底数都是一样的,指数也差不多,就可以预处理。
但是mod的最大值可能达到1e8.
所以我们预处理1-1e4的,然后再预处理c1e4的1-1e4的。
最后时间复杂度就去了一个log,不用卡常也过了。
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> using namespace std; const int N=100005; inline char gc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } //#define gc getchar inline int rd() { register int x=0;register char ch=gc(); while(!isdigit(ch)) ch=gc(); while(isdigit(ch)) {x=x*10ll+(ch^48);ch=gc();} return x; } struct Segtree{ int sum;int l,r;short tag; }t[N<<2]; int a[N],phi[N],n,m,p,c,lim,l,r,low_er[50005][105],high_er[50005][105],f[50005][105]; bool flag; int ksm(int z,int mod) { if(z<=10000) return low_er[z][mod]; return 1ll*high_er[z/10000][mod]*low_er[z%10000][mod]%phi[mod]; } int ksm(long long d,int z,int mod) { long long res=1ll; while(z) { if(z&1) res=res*d; d=d*d; if(res>=mod) res%=mod; if(d>=mod) d%=mod; z>>=1; } return res; } int work(int d,int z) { int res=d; if(res>=phi[z]) res=res%phi[z]+phi[z]; while(z) { flag=0; res=ksm(res,phi[z-1]); if(flag) res+=phi[z-1]; z--; } return res; } #define ls (cur<<1) #define rs (cur<<1|1) #define mid (l+r>>1) void build(int l,int r,int cur){ t[cur].l=l,t[cur].r=r; if(l==r) { t[cur].sum=a[l]; return; } build(l,mid,ls); build(mid+1,r,rs); t[cur].sum=(t[ls].sum+t[rs].sum)%p; } void update(int cur) { if(t[cur].tag>=lim) return; if(l>t[cur].r||r<t[cur].l) return; if(t[cur].l==t[cur].r) { t[cur].tag++; t[cur].sum=f[t[cur].l][t[cur].tag]; return; } update(ls); update(rs); t[cur].sum=(t[ls].sum+t[rs].sum)%p; t[cur].tag=min(t[ls].tag,t[rs].tag); } long long query(int cur) { if(l>t[cur].r||r<t[cur].l) return 0; if(l<=t[cur].l&&t[cur].r<=r) return t[cur].sum; return (query(ls)+query(rs))%p; } #undef ls #undef rs #undef mid int getphi(long long x) { int res=x,sq=sqrt(x); for(int i=2;i<=sq;i++) { if(!(x%i)) { while(!(x%i)) x/=i; res=res/i*(i-1); } } if(x-1) res=res/x*(x-1); return res; } int cal(int x,int num,int d) { if(!num) return x%phi[d]; int t=cal(x,num-1,d+1); if(pow(c,num-1)*x>=phi[d+1]) t+=phi[d+1]; return ksm(t,d); } void pre() { for(int i=0;i<=10000;i++) { for(int j=0;j<=lim;j++) { low_er[i][j]=ksm(c,i,phi[j]); high_er[i][j]=ksm(ksm(c,10000,phi[j]),i,phi[j]); } } for(int i=1;i<=n;i++) { if(!a[i]) { f[i][1]=1; for(int j=2;j<=lim;j++) { f[i][j]=cal(1,j-1,0); } } else for(int j=1;j<=lim;j++) f[i][j]=cal(a[i],j,0); } } signed main() { n=rd();m=rd(),p=rd();c=rd(); phi[0]=p; while(phi[lim]^1) lim++,phi[lim]=getphi(phi[lim-1]); phi[++lim]=1; for(int i=1;i<=n;i++) a[i]=rd(); pre(); build(1,n,1); int opt; while(m--) { opt=rd();l=rd();r=rd(); switch (opt) { case 0: {update(1);break;} case 1: {printf("%d ",query(1));break;} } } return 0; }