題解 CF1109E 【Sasha and a Very Easy Test】
阿新 • • 發佈:2020-12-01
前置知識:尤拉定理(擴充套件費馬小定理),基本線段樹操作
題意
十分簡潔,不多贅述。
注意 \(mod\) 可以不為質數,每個單點除操作保證能整除。
思路
若 \(mod\) 是質數就好做了(不然怎麼會是黑題),但 \(mod\) 不是質數代表在單點除時不能直接用費馬小定理邊乘邊模。
可以考慮使用擴充套件費馬定理:
\[a^{\varphi(p)}=1\mod p ~~(\gcd(a,p)=1) \]發現小於 \(1e9\) 的每個數質因數個數不會超過 \(9\) 個,可以想到將所有要進行操作的數分成兩部分,一部分質因子全是 \(mod\) 的質因子,開一個大小為 \(10\)
注意細節,可以參考程式碼。
另附上 \(\varphi(n)\) 的求法:
\[\varphi(n)=n\times\prod^{x}_{i=1}\frac{p_i}{p_i-1} \]不要像我 \(\varphi\) 求錯了調1h
時間複雜度 \(\texttt{O(10NlogN)}\) (遠遠達不到這個上限)。
程式碼
#include <bits/stdc++.h> using namespace std; #define ls n << 1 #define rs n << 1 | 1 #define int long long const int N = 1e5; inline int read() { int s = 0; register bool neg = 0; register char c = getchar(); for (; c < '0' || c > '9'; c = getchar()) neg |= (c == '-'); for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar()) ; s = (neg ? -s : s); return s; } int a,mod,b,p[10],top,q[N+10],t[N+10][10],add[10],pp; struct segment { int l,r,val,lazy1[10],lazy2,lazy3; } s[N*4+10]; inline int get_phi(int n) { int ans = n; for (int i = 2; i*i <= n; i++) { if (!(n%i)) { ans = 1ll * ans * (i - 1) / i; while (!(n%i))n /= i; } } if (n > 1)ans = 1ll * ans * (n - 1) / n; return ans; } inline void get(int n) { int qq=sqrt(n); for(int i=2;i<=qq;i++) { if(n%i==0) { p[++top]=i; while(n%i==0) n/=i; } } if(n!=1) p[++top]=n; } inline int qpow(int n,int m) { int res=1; for(;m;m>>=1) { if(m&1) res=res*n%mod; n=n*n%mod; } return res; } inline int calc(int n) { int res=1; for(int i=1;i<=top;i++) res=(res*qpow(p[i],t[n][i]))%mod; return res; } inline void up(int n) { s[n].val=(s[ls].val+s[rs].val)%mod; } inline void down(int n) { s[ls].val=s[ls].val*s[n].lazy2%mod; s[rs].val=s[rs].val*s[n].lazy2%mod; s[ls].lazy2=s[ls].lazy2*s[n].lazy2%mod; s[rs].lazy2=s[rs].lazy2*s[n].lazy2%mod; s[ls].lazy3=s[ls].lazy3*s[n].lazy3%mod; s[rs].lazy3=s[rs].lazy3*s[n].lazy3%mod; s[n].lazy2=s[n].lazy3=1; for(int i=1;i<=top;i++) { s[ls].lazy1[i]+=s[n].lazy1[i]; s[rs].lazy1[i]+=s[n].lazy1[i]; s[n].lazy1[i]=0; } return; } inline void build(int n,int l,int r) { s[n].l=l; s[n].r=r; s[n].lazy2=s[n].lazy3=1; memset(s[n].lazy1,0,sizeof(s[n].lazy1)); if(l==r) { s[n].val=q[l]*calc(l)%mod; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); up(n); } inline void div(int n,int m,int k) { if(s[n].l==s[n].r) { q[m]=q[m]*s[n].lazy3%mod; s[n].lazy3=1; for(int i=1;i<=top;i++) { t[m][i]+=s[n].lazy1[i]; s[n].lazy1[i]=0; while(k%p[i]==0) t[m][i]--,k/=p[i]; } q[m]=q[m]*qpow(k,pp-1)%mod; s[n].val=q[m]*calc(m)%mod; return; } down(n); int mid=(s[n].l+s[n].r)>>1; if(m<=mid) div(ls,m,k); else div(rs,m,k); up(n); } inline void times(int n,int l,int r,int k,int _k) { if(s[n].l>=l&&s[n].r<=r) { s[n].val=s[n].val*k%mod; s[n].lazy2=s[n].lazy2*k%mod; s[n].lazy3=s[n].lazy3*_k%mod; for(int i=1;i<=top;i++) s[n].lazy1[i]+=add[i]; return; } down(n); int mid=(s[n].l+s[n].r)>>1; if(l<=mid) times(ls,l,r,k,_k); if(mid<r) times(rs,l,r,k,_k); up(n); } inline int query(int n,int l,int r) { if(s[n].l>=l&&s[n].r<=r) return s[n].val; down(n); int mid=(s[n].l+s[n].r)>>1,res=0; if(l<=mid) res=(res+query(ls,l,r))%mod; if(mid<r) res=(res+query(rs,l,r))%mod; return res; } signed main() { // freopen("in.txt","r",stdin); a=read(); mod=read(); pp=get_phi(mod); int opt,x,y,z; get(mod); for(int i=1;i<=a;i++) { q[i]=read(); for(int j=1;j<=top;j++) { while(q[i]%p[j]==0) { q[i]/=p[j]; t[i][j]++; } } } build(1,1,a); b=read(); for(int i=1;i<=b;i++) { opt=read(); x=read(); y=read(); if(opt==1) { z=read(); if(z==1) continue; int _z=z; for(int j=1;j<=top;j++) { add[j]=0; while(_z%p[j]==0) _z/=p[j],add[j]++; } times(1,x,y,z,_z); } else if(opt==2) div(1,x,y); else printf("%lld\n",query(1,x,y)); } return 0; }