[六省聯考2017]相逢是問候(線段樹+拓展尤拉定理)
阿新 • • 發佈:2019-01-06
好題啊!
調了一箇中午,發現有一條語句 \(RE\) 了。在 \(windows\) 下沒關係,\(linux\) 下有問題,大大的問題。
while(phi[tot]!=1) phi[++tot]=calc_phi(phi[tot-1]);
算是拓展尤拉定理的題吧。線段樹只是一個工具,最主要還是暴力修改。因為 \(\varphi\) 不斷套下去最多會有 \(\lfloor \log n\rfloor\) 層,所以我們對於每一層暴力算一遍,加上快速冪,時間複雜度 \(O(n\log^3 n)\),顯然可能被卡。怎麼優化呢?
將 \(O(\log n)\) 的快速冪換成 \(O(1)\)
\(Code\ Below:\)
#include <bits/stdc++.h> #define int long long #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; const int maxn=100000+10; const int base=(1<<14)-1; int n,m,p,c,a[maxn],sum[maxn<<2],Min[maxn<<2],pw1[55][maxn],pw2[55][maxn],phi[maxn],tot; bool b1[55][maxn],b2[55][maxn],flag; inline int read(){ register int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return (f==1)?x:-x; } int calc_phi(int n){ int ans=n,m=sqrt(n); for(int i=2;i<=m;i++){ if(n%i==0){ ans=ans/i*(i-1); while(n%i==0) n/=i; } } if(n>1) ans=ans/n*(n-1); return ans; } void pre(){ int tmp=p;phi[0]=p; while(tmp!=1) tmp=calc_phi(tmp),phi[++tot]=tmp; phi[++tot]=1; for(int i=0;i<=tot;i++){ pw1[i][0]=1; for(int j=1;j<=base+1;j++){ pw1[i][j]=pw1[i][j-1]*c; if(pw1[i][j]>=phi[i]) b1[i][j]=1,pw1[i][j]%=phi[i]; b1[i][j]|=b1[i][j-1]; } } for(int i=0;i<=tot;i++){ pw2[i][0]=1; b2[i][1]=b1[i][base+1]; for(int j=1;j<=base;j++){ pw2[i][j]=pw2[i][j-1]*pw1[i][base+1]; if(pw2[i][j]>=phi[i]) b2[i][j]=1,pw2[i][j]%=phi[i]; b2[i][j]|=b2[i][j-1]; } } } int calc(int a,int dep){ flag=0; int x=a&base,y=(a>>14)&base; int ans=pw1[dep][x]*pw2[dep][y]; if(ans>=phi[dep]) flag=1,ans%=phi[dep]; flag|=b1[dep][x]|b2[dep][y]; return ans; } int dfs(int a,int dep,int lim){ flag=0; if(dep==lim){ if(a>=phi[dep]) flag=1,a%=phi[dep]; return a; } int b=dfs(a,dep+1,lim); return calc(flag?b+phi[dep+1]:b,dep); } inline void pushup(int rt){ sum[rt]=(sum[lson]+sum[rson])%p; Min[rt]=min(Min[lson],Min[rson]); } void build(int l,int r,int rt){ if(l == r){ sum[rt]=a[l]; return ; } int mid=(l+r)>>1; build(l,mid,lson); build(mid+1,r,rson); pushup(rt); } void update(int L,int R,int l,int r,int rt){ if(Min[rt]>=tot) return ; if(l == r){ Min[rt]++; sum[rt]=dfs(a[l],0,Min[rt]); return ; } int mid=(l+r)>>1; if(L <= mid) update(L,R,l,mid,lson); if(R > mid) update(L,R,mid+1,r,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(L <= l && r <= R){ return sum[rt]; } int mid=(l+r)>>1,ans=0; if(L <= mid) ans=(ans+query(L,R,l,mid,lson))%p; if(R > mid) ans=(ans+query(L,R,mid+1,r,rson))%p; return ans; } signed main() { n=read(),m=read(),p=read(),c=read(); for(int i=1;i<=n;i++) a[i]=read(); pre();build(1,n,1); int op,l,r; while(m--){ op=read(),l=read(),r=read(); if(op==0) update(l,r,1,n,1); if(op==1) printf("%lld\n",query(l,r,1,n,1)); } return 0; }