这道题比赛的时候并没有AC,赛后看别人博客学会的,其实我一开始的思路还是比较像的,这道题看到的第一眼想到了网络赛的那个单点修改的,因为Mod不是质数,但是题目说了单点除的数在前面一定会出现一个乘这个数,所以连线搞就好了,然后这题并不能这样做。然后我就想着把Mod质因数分解,如果Mod = p1 * p2 * … Pn这种,所有质数的指数都是1的话,这个时候直接维护每一个质数的模的乘积,然后最后答案用一个CRT就搞定了,然后以为数据会给的这么水,结果发现样例都贵了。。。
下面说一下正解:
1:Mod 质因数分解。得到Mod的所有质因数fac[fac_cnt]
2:因为题目说了一定能够整除,所有我们线段树维护cnt[i],该区间乘积中Mod的第i个质因数的指数,然后我们发现
num[i]=∏fac[p[i]]q[i]∗k
那么剩下来的这个k,满足gcd(k,Mod) = 1。那么我们需要额外维护一个k。
3:对于M操作:M L R x 我们先把x写成上面那种形式,那么对于Mod的质因数,乘法就变成了指数的加法,对于k只需要乘起来就好了。
4:对于D操作:D L R x 和上面一样,但是除法变成了指数的减法,对于k变成逆元就搞定了
本题坑点:一开始的数可能是0,乘的数也可能是0;因为这个TLE了2发。
下面附上AC代码:
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define lrt rt<<1
#define rrt rt<<1|1
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn = 10010;
int n;
int fac[35],fac_cnt;
LL num[maxn];
LL Mod;
void exgcd(LL a,LL b,LL& d,LL& x,LL& y){
if(!b) {d = a; x = 1; y = 0;}
else {exgcd(b,a%b,d,y,x); y -= x*(a/b);}
}
LL inv(LL a,LL p){
LL d,x,y;
exgcd(a,p,d,x,y);
return d == 1 ? (x+p)%p : -1;
}
LL quickpow(LL a,LL x,LL p){
LL ans = 1;
while(x){
if(x&1) ans = (ans*a)%p;
a = (a*a)%p;
x >>= 1;
}
return ans;
}
void init(){
scanf("%d%d",&n,&Mod);
LL m = Mod;
fac_cnt = 0;
for(int i = 2;i*i <= m;i ++) if(m % i == 0){
fac[fac_cnt++] = i;
while(m % i == 0) m /= i;
}
if(m != 1) fac[fac_cnt++] = m;
FOR(i,1,n+1) scanf("%lld",&num[i]);
}
struct Tree{
int l,r;
LL cnt[30];
LL lazy[30];
LL x;
LL lazyx;
}tree[maxn<<2];
void PushUp(int rt){
FOR(i,0,fac_cnt) tree[rt].cnt[i] = tree[lrt].cnt[i] + tree[rrt].cnt[i];
tree[rt].x = (tree[lrt].x * tree[rrt].x)%Mod;
}
void UpDate(int rt,LL* a,LL y){
FOR(i,0,fac_cnt) tree[rt].lazy[i] += a[i];
FOR(i,0,fac_cnt) tree[rt].cnt[i] += a[i]*(tree[rt].r-tree[rt].l+1);
tree[rt].lazyx = (tree[rt].lazyx*y)%Mod;
LL tem = quickpow(y,(tree[rt].r-tree[rt].l+1),Mod);
tree[rt].x = (tree[rt].x*tem)%Mod;
}
void PushDown(int rt){
UpDate(lrt,tree[rt].lazy,tree[rt].lazyx);
UpDate(rrt,tree[rt].lazy,tree[rt].lazyx);
FOR(i,0,fac_cnt) tree[rt].lazy[i] = 0;
tree[rt].lazyx = 1;
}
void Build(int rt,int l,int r){
tree[rt].l = l; tree[rt].r = r; tree[rt].lazyx = 1;
FOR(i,0,fac_cnt) tree[rt].lazy[i] = 0;
if(l == r){
FOR(i,0,fac_cnt){
tree[rt].cnt[i] = 0;
if(num[l] == 0) continue;
while(num[l] % fac[i] == 0) {tree[rt].cnt[i]++;num[l] /= fac[i];}
}
tree[rt].x = num[l];
return;
}
int mid = (l+r)>>1;
Build(lson);
Build(rson);
PushUp(rt);
}
void Modify(int rt,int l,int r,LL* a,LL y){
if(tree[rt].l == l && tree[rt].r == r){
UpDate(rt,a,y);
return;
}
PushDown(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(r <= mid) Modify(lrt,l,r,a,y);
else if(l > mid) Modify(rrt,l,r,a,y);
else{
Modify(lson,a,y);
Modify(rson,a,y);
}
PushUp(rt);
}
struct Ans{
LL cnt[30];
LL x;
};
Ans Query(int rt,int l,int r){
if(tree[rt].l == l && tree[rt].r == r){
Ans rhs;
FOR(i,0,fac_cnt) rhs.cnt[i] = tree[rt].cnt[i];
rhs.x = tree[rt].x;
return rhs;
}
PushDown(rt);
int mid = (tree[rt].l + tree[rt].r)>>1;
if(r <= mid) return Query(lrt,l,r);
else if(l > mid) return Query(rrt,l,r);
else{
Ans rhs1,rhs2;
rhs1 = Query(lson);
rhs2 = Query(rson);
Ans rhs;
FOR(i,0,fac_cnt) rhs.cnt[i] = rhs1.cnt[i] + rhs2.cnt[i];
rhs.x = (rhs1.x*rhs2.x)%Mod;
return rhs;
}
}
void work(){
Build(1,1,n);
int q;
char op[2];
scanf("%d",&q);
while(q--){
int l,r;
LL w;
scanf("%s%d%d",op,&l,&r);
if(op[0] == 'Q'){
Ans res = Query(1,l,r);
LL ans = 1;
ans = (ans*res.x)%Mod;
if(!ans) {printf("0\n");continue;}
FOR(i,0,fac_cnt) ans = (ans*quickpow(fac[i],res.cnt[i],Mod))%Mod;
printf("%lld\n",ans);
}
else if(op[0] == 'M'){
scanf("%lld",&w);
LL a[30],y;
memset(a,0,sizeof(a));
if(!w) {FOR(i,0,fac_cnt) a[i] = 0; y = 0;}
else{
FOR(i,0,fac_cnt) while(w % fac[i] == 0){
a[i] ++;
w /= fac[i];
}
y = w;
}
Modify(1,l,r,a,y);
}
else{
scanf("%lld",&w);
LL a[30],y;
memset(a,0,sizeof(a));
FOR(i,0,fac_cnt) while(w % fac[i] == 0){
a[i] ++;
w /= fac[i];
}
if(w == 1) y = w;
else y = inv(w,Mod);
FOR(i,0,fac_cnt) a[i] = -a[i];
Modify(1,l,r,a,y);
}
}
}
int main(){
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",++tCase);
init();
work();
}
return 0;
}