题解 CF1109E【Sasha and a Very Easy Test】
题意
给你一个长为 $n$ 的序列 $a$ 和一个数 $p$,有 $q$ 次操作,操作有 $3$ 种,分别是:
1 l r x,对 $\forall i\in[l,r],a_i\gets a_i\times x$;2 c x,令 $a_c\gets \dfrac{a_c}{x}$,保证 $x\mid a_c$;3 l r,查询 $\displaystyle\left(\sum_{i=l}^ra_i\right) \bmod p$。
时限 2.5s,$1\le n,q\le 10^5$,$1\le a_i,x\le 10^5$,$2\le p\le 10^9+9$。
思路
看到这个除法操作是非常难直接维护的,模数 $p$ 也不是质数,所以可以向维护质因子次数的方面想。
质数有很多,不可能每一个都直接维护,考虑维护质数的原因是 $p$ 不保证是质数,$x$ 不一定有逆元。而 $x$ 在模 $p$ 意义下有逆元当且仅当 $\gcd(x,p)=1$。考虑将 $x,p$ 分别分解质因数,$x$ 中不是 $p$ 的因数的质因数可以直接用 $x^{φ(p)-1}$ 计算逆元,只有 $p$ 的质因子需要特殊维护。
可以发现,由于 $p\le 10^9+9$,$p$ 的不同因数最多只有 $k=9$ 个,可以直接维护。使用线段树,标记存下这些信息即可。
时间复杂度 $O(kn\log n)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=5e5+10;
int n,q,p,phi,cnt,sp[15];
inline int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%p;
x=1ll*x*x%p;
y>>=1;
}
return res;
}
struct node{
int ep,op[15];
inline void init(int x){
for(int i=1;i<=cnt;i++){
op[i]=0;
while(x%sp[i]==0)
op[i]++,x/=sp[i];
}
ep=x;
}
inline int getv(){
int res=ep;
for(int i=1;i<=cnt;i++)
res=1ll*res*qpow(sp[i],op[i])%p;
return res;
}
inline void set(){
ep=1;
memset(op,0,sizeof(op));
}
inline friend node operator*(const node &a,const node &b){
node c;
c.ep=1ll*a.ep*b.ep%p;
for(int i=1;i<=cnt;i++)
c.op[i]=a.op[i]+b.op[i];
return c;
}
}s[N];
struct Segment_Tree{
struct Node{
int sum,tagm;
node tagd;
}a[N<<2];
#define ls (rt<<1)
#define rs (rt<<1|1)
inline void pushdown(int rt){
a[ls].sum=1ll*a[ls].sum*a[rt].tagm%p;
a[rs].sum=1ll*a[rs].sum*a[rt].tagm%p;
a[ls].tagm=1ll*a[ls].tagm*a[rt].tagm%p;
a[rs].tagm=1ll*a[rs].tagm*a[rt].tagm%p;
a[ls].tagd=a[ls].tagd*a[rt].tagd;
a[rs].tagd=a[rs].tagd*a[rt].tagd;
a[rt].tagm=1,a[rt].tagd.set();
}
inline void pushup(int rt){
a[rt].sum=(a[ls].sum+a[rs].sum)%p;
}
inline void build(int rt,int l,int r){
a[rt].tagm=1,a[rt].tagd.set();
if(l==r){
a[rt].sum=s[l].getv();
return ;
}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(rt);
}
inline void multi(int rt,int l,int r,int L,int R,node v){
if(L<=l&&r<=R){
a[rt].sum=1ll*a[rt].sum*v.getv()%p;
a[rt].tagm=1ll*a[rt].tagm*v.getv()%p;
a[rt].tagd=a[rt].tagd*v;
return ;
}
pushdown(rt);
int mid=l+r>>1;
if(L<=mid) multi(ls,l,mid,L,R,v);
if(R>mid) multi(rs,mid+1,r,L,R,v);
pushup(rt);
}
inline void dived(int rt,int l,int r,int p,int v){
if(l==r){
s[p]=s[p]*a[rt].tagd;
a[rt].tagd.set();
for(int i=1;i<=cnt;i++)
while(v%sp[i]==0)
s[p].op[i]--,v/=sp[i];
s[p].ep=1ll*s[p].ep*qpow(v,phi-1)%(::p);
a[rt].sum=s[p].getv();
return ;
}
pushdown(rt);
int mid=l+r>>1;
if(p<=mid) dived(ls,l,mid,p,v);
else dived(rs,mid+1,r,p,v);
pushup(rt);
}
inline int query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return a[rt].sum;
pushdown(rt);
int mid=l+r>>1,res=0;
if(L<=mid) res=(res+query(ls,l,mid,L,R))%p;
if(R>mid) res=(res+query(rs,mid+1,r,L,R))%p;
return res;
}
}T;
int main(){
n=read(),p=read();
int tmp;tmp=phi=p;
for(int i=2;i*i<=p;i++){
if(tmp%i==0){
sp[++cnt]=i;
phi=phi/i*(i-1);
while(tmp%i==0) tmp/=i;
}
}
if(tmp!=1){
sp[++cnt]=tmp;
phi=phi/tmp*(tmp-1);
}
for(int i=1;i<=n;i++)
s[i].init(read());
q=read();
T.build(1,1,n);
while(q--){
int opt=read(),l=read(),r=read();
if(opt==1){
int x=read();
node tmp;tmp.init(x);
T.multi(1,1,n,l,r,tmp);
}else if(opt==2){
T.dived(1,1,n,l,r);
}else{
write(T.query(1,1,n,l,r)),putc('\n');
}
}
flush();
}
再见 qwq~

浙公网安备 33010602011771号