CF1109E Sasha and a Very Easy Test 题解
作者:互联网
题意简述:
维护一个序列,给定三种操作:区间乘,单点除,区间求和。任意模数。
思路:
操作就这么个操作,线段树套上就没了,重点在于任意模数的除法,不然这也不会是黑题了。
除数与模数不一定互质那就没法求逆元了。既然如此那就把数分为互质的部分和不互质的部分,不就解决了嘛?
具体的嗦,将模数分解质因数,一个数也可以拆分分为包含这些质因数的部分与不包含的部分,包含的那部分特殊处理,不包含的就互质了,可以用逆元。即:
\[mod=p_1^{c_1}×p_2^{c_2}×\cdots×p_{cnt}^{c_{cnt}} \]\[x=a×p_1^{t_1}×p_2^{t_2}×\cdots×p_{cnt}^{t_{cnt}},\gcd(a,mod)=1 \]其中\(mod\)每个质因子的次数没必要知道,而其他数是需要的。
在处理时,对于互质的部分\(a\),可以直接算,除法就用逆元(exgcd 或欧拉定理)。对于不互质的部分\(p\),就用次数相加减,在查询时再用快速幂算一遍。
关于线段树,由于除法是单点的,所以在线段树上我们没必要对每一处权值都这么处理,只处理单点即可。
具体的处理,pushup 与正常无异,但是 lazy 与 pushdown 需要特殊处理。并且对于每个单点的操作,可以直接用 lazy 储存,也只需要在做除法的时候,对于单点将 lazy 用掉,更新权值。所以为了提升效率,lazy 需要未经拆分的,应对区间乘操作,与拆分过的,应对单点除操作。
既然都要分解质因数了,那就顺便求个欧拉函数,用欧拉定理求逆元岂不美哉?关于欧拉函数与欧拉定理:
\[\varphi(n)=n×\prod_{i=1}^{cnt}\frac{p_i-1}{p_i} \]\[a^{\varphi(p)}\equiv 1\quad mod\;p\;(\gcd(a,p)=1) \]\[a^{\varphi(p)-1}\equiv a^{-1}\quad mod\;p\;(\gcd(a,p)=1) \]顺便,对于逆元可以整个小记忆化...不过询问并没有那么多所以优化不大
代码 qwq:
#include<bits/stdc++.h>
#define ttT template <typename T>
#define EL puts("Elaina")
#define reg register int
#define qwq 0
using namespace std;
inline char gc(){
static char buf[1<<21],*p1,*p2;
if(p1==p2){p1=buf,p2=buf+fread(buf,1,1<<21,stdin);if(p1==p2)return EOF;}
return *p1++;
}
ttT inline void read(T &x){
x=0;int f=1;char ch=gc();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
x*=f;
}
typedef long long ll;
const int maxn=1e5+3;
int n,mod,phi,p[11],pcnt,invv[maxn];
inline int qpow(int a,int b){
int ans=1;a%=mod;
for(;b;b>>=1,a=1ll*a*a%mod)
if(b&1)ans=1ll*ans*a%mod;
return ans;
}
inline int inv(int x){
return invv[x]?invv[x]:invv[x]=qpow(x,phi-1);
}
struct num{
int x,np[11];
num(){};
num(int n){
x=0,memset(np,0,sizeof(np));
if(n==1){x=1;return;}
for(reg i=1;i<=pcnt;++i)
while(n%p[i]==0)np[i]++,n/=p[i];
x=n;
}
inline int calc(){
int ans=x;
for(reg i=1;i<=pcnt;++i)ans=1ll*ans*qpow(p[i],np[i])%mod;
return ans;
}
};
#define lt (k<<1)
#define rt (k<<1|1)
num a[maxn];
struct node{
int l,r,x,lzy;
num lazy;
}t[maxn<<2];
inline void pushup(int k){
t[k].x=(t[lt].x+t[rt].x)%mod;
}
inline void pushdown(int k){
t[lt].x=1ll*t[lt].x*t[k].lzy%mod,t[rt].x=1ll*t[rt].x*t[k].lzy%mod;
t[lt].lzy=1ll*t[lt].lzy*t[k].lzy%mod,t[rt].lzy=1ll*t[rt].lzy*t[k].lzy%mod;
t[lt].lazy.x=1ll*t[lt].lazy.x*t[k].lazy.x%mod;
t[rt].lazy.x=1ll*t[rt].lazy.x*t[k].lazy.x%mod;
for(reg i=1;i<=pcnt;++i){
t[lt].lazy.np[i]+=t[k].lazy.np[i];
t[rt].lazy.np[i]+=t[k].lazy.np[i];
t[k].lazy.np[i]=0;
}
t[k].lzy=t[k].lazy.x=1;
}
inline void build(int k,int l,int r){
t[k].l=l,t[k].r=r,t[k].lzy=1,t[k].lazy=num(1);
if(l==r)t[k].x=a[l].calc();
else{
int mid=(l+r)>>1;
build(lt,l,mid);
build(rt,mid+1,r);
pushup(k);
}
}
inline void updata(int k,int L,int R,int x,num xx){
if(L<=t[k].l&&t[k].r<=R){
t[k].x=1ll*t[k].x*x%mod;
t[k].lzy=1ll*t[k].lzy*x%mod;
t[k].lazy.x=1ll*t[k].lazy.x*xx.x%mod;
for(reg i=1;i<=pcnt;++i)t[k].lazy.np[i]+=xx.np[i];
}
else{
int mid=(t[k].l+t[k].r)>>1;
pushdown(k);
if(L<=mid)updata(lt,L,R,x,xx);
if(R>mid)updata(rt,L,R,x,xx);
pushup(k);
}
}
inline void updata(int k,int pi,int x){
if(t[k].l==t[k].r){
a[pi].x=1ll*a[pi].x*t[k].lazy.x%mod,t[k].lazy.x=1;
for(reg i=1;i<=pcnt;++i){
a[pi].np[i]+=t[k].lazy.np[i];
while(x%p[i]==0)a[pi].np[i]--,x/=p[i];
t[k].lazy.np[i]=0;
}
a[pi].x=1ll*a[pi].x*inv(x)%mod;
t[k].x=a[pi].calc();
}
else{
int mid=(t[k].l+t[k].r)>>1;
pushdown(k);
if(pi<=mid)updata(lt,pi,x);
else updata(rt,pi,x);
pushup(k);
}
}
inline int query(int k,int L,int R){
if(L<=t[k].l&&t[k].r<=R)return t[k].x;
else{
int mid=(t[k].l+t[k].r)>>1,ans=0;
pushdown(k);
if(L<=mid)ans=(1ll*ans+query(lt,L,R))%mod;
if(R>mid)ans=(1ll*ans+query(rt,L,R))%mod;
return ans;
}
}
void solve(){
read(n),read(mod);
int dom=phi=mod;
for(reg i=2;i*i<=mod;++i)
if(dom%i==0){
p[++pcnt]=i;
phi=phi/i*(i-1);
while(dom%i==0)dom/=i;
}
if(dom^1)p[++pcnt]=dom,phi=phi/dom*(dom-1);
for(reg i=1,x;i<=n;++i)
read(x),a[i]=num(x);
build(1,1,n);
int q,opt,l,r,x;
read(q);
while(q--){
read(opt);
if(opt==1){
read(l),read(r),read(x);
updata(1,l,r,x,num(x));
}
else if(opt==2){
read(l),read(x);
updata(1,l,x);
}
else{
read(l),read(r);
printf("%d\n",query(1,l,r));
}
}
}
int main(){
solve();
return qwq;
}
标签:lazy,单点,Very,题解,CF1109E,int,ans,互质,mod 来源: https://www.cnblogs.com/muel-imj/p/16025443.html