P3747 [六省聯考2017]相逢是問候 尤拉公式
阿新 • • 發佈:2020-12-24
題意:
分析:
- 暴力
\(O(nm\log )\) 模擬,\(p=2\) 的點判奇偶性,期望得分 \(20pts\)
- 正解
我們發現 \(c\) 恆定,所以經過一系列操作後,每一個元素變為了 \(\large x^{c^{c^{\dots {a_i}}}}\)
我們發現這個形式很尤拉定理,因為尤拉定理對於單個數一旦累計次方超過一定程度,值就成 \(1\) 不變了,我們由已知結論得到,這個次數大約是 \(\log p\) 級別的,也就是說對於每一個元素只有前 $\log $ 次操作是有效的
所以我們預處理出來每一個數前 \(\log\) 次操作,然後按照尤拉定理分 $\log $ 層,所以預處理的複雜度是 \(O(n\log^2)\)
(因為我們使用了光速冪,所以複雜度是 \(2\) 只 $\log $)
然後我們需要線段樹維護區間修改操作次數的最小值,一旦區間修改操作大於 $ \log$ 直接返回 ,然後順便維護區間和值
程式碼:
#include<bits/stdc++.h> #define lc rt<<1 #define rc rt<<1|1 using namespace std; namespace zzc { long long read() { long long x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } const long long maxn = 5e4+5; const long long maxs = 1e4+5; long long cnt[maxn<<2],v[maxn<<2]; long long s1[maxs][30],s2[maxs][30],f[maxn][30][30],a[maxn],g[30],phi[30]; bool b1[maxs][30],b2[maxs][30],b[maxn][30][30]; long long n,m,p,c,len; long long get_phi(long long x) { long long res=x; for(int i=2;i*i<=x;i++) { if(x%i) continue; res=res*(i-1)/i; while(x%i==0) x/=i; } if(x>1) res=res*(x-1)/x; return res; } void init() { long long tmp=p; phi[0]=tmp; while(tmp!=1) { tmp=get_phi(tmp); phi[++len]=tmp; } phi[++len]=1; for(int i=0;i<=len;i++) g[i]=__gcd(c,phi[i]); //¹âËÙÃÝ for(int j=0;j<=len;j++) { s2[0][j]=1; for(int i=1;i<=10000;i++) { s2[i][j]=s2[i-1][j]*c; if(s2[i][j]>=phi[j]) { s2[i][j]%=phi[j]; b2[i][j]=true; } b2[i][j]|=b2[i-1][j]; } } for(int j=0;j<=len;j++) { s1[0][j]=1; b1[1][j]=b2[10000][j]; for(int i=1;i<=10000;i++) { s1[i][j]=s1[i-1][j]*s2[10000][j]; if(s1[i][j]>=phi[j]) { s1[i][j]%=phi[j]; b1[i][j]=true; } b1[i][j]|=b1[i-1][j]; } } for(int i=1;i<=n;i++) { for(int j=0;j<=len;j++) { f[i][0][j]=a[i]%phi[j]; if(a[i]>=phi[j]) b[i][0][j]=true; } for(int j=1;j<=len;j++) { f[i][j][len]=0; for(int k=0;k<len;k++) { f[i][j][k]=s1[f[i][j-1][k+1]/10000][k]*s2[f[i][j-1][k+1]%10000][k]; b[i][j][k]=b1[f[i][j-1][k+1]/10000][k]|b2[f[i][j-1][k+1]%10000][k]; if(f[i][j][k]>=phi[k]) { f[i][j][k]%=phi[k]; b[i][j][k]=true; } if(g[k]!=1&&b[i][j-1][k+1]) { f[i][j][k]=f[i][j][k]*s1[phi[k+1]/10000][k]%phi[k]*s2[phi[k+1]%10000][k]; if(f[i][j][k]>=phi[k]) { f[i][j][k]%=phi[k]; b[i][j][k]=true; } b[i][j][k]|=b1[phi[k+1]/10000][k]|b2[phi[k+1]%10000][k]; } } } } return ; } void pushup(int rt) { v[rt]=v[lc]+v[rc]; cnt[rt]=min(cnt[lc],cnt[rc]); } void build(int rt,int l,int r) { if(l==r) { v[rt]=a[l]; cnt[rt]=0; return ; } int mid=(l+r)>>1; build(lc,l,mid);build(rc,mid+1,r); pushup(rt); } void modify(int rt,int l,int r,int ql,int qr) { if(ql>r||l>qr||cnt[rt]>=len) return ; if(l==r) { cnt[rt]++; v[rt]=f[l][cnt[rt]][0]%p; return ; } int mid=(l+r)>>1; if(cnt[lc]<len) modify(lc,l,mid,ql,qr); if(cnt[rc]<len) modify(rc,mid+1,r,ql,qr); pushup(rt); } long long query(int rt,int l,int r,int ql,int qr) { if(ql>r||qr<l) return 0; if(ql<=l&&r<=qr) return v[rt]%p; int mid=(l+r)>>1; return (query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr))%p; } void work() { int opt,l,r; n=read();m=read();p=read();c=read(); for(int i=1;i<=n;i++) a[i]=read(); init(); build(1,1,n); for(int i=1;i<=m;i++) { opt=read();l=read();r=read(); if(opt==0) modify(1,1,n,l,r); else printf("%lld\n",query(1,1,n,l,r)); } } } int main() { zzc::work(); return 0; }