题意:给出一个序列,对这个序列进行了三种操作,一种是查询。查询区间[l. r]内序列的乘积,一种是乘法修改,将区间[l. r]内全部元素乘以一个数,另一种操作是区间除法修改,保证除法合法,输出时将结果模除m(m可能为合数)。
思路:如果这道题m是质数那么就是一个裸的线段树,现在m可能为合数,逆元可能不存在,那么考虑把一个数a分解成b*c的形式,使得b是由m的质因子相乘得来,c与m互质,那么对于c我们就可以用线段树+扩展欧几里得求逆元来乱搞了。
现在问题是b,因为m的质因子的个数不超过10,我们可以考虑维护区间内m的每个质因子被乘的次数,然后查询的时候查询每个质因子被乘了多少次然后来一个快速幂,最后乘上之前那个互素的部分的结果就是最终答案。
注意:这道题有一个坑点,因为乘法操作时可能乘以0,而分解0的时候如果不特判会无限循环,因为0整除任意数,注意一下这点再细心点应该没啥问题了.....
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 10100;
//const int INF = 0x3f3f3f3f;
int n, m, p, a[MAXN], Q;
int prime[15], modify[15];
LL addv[15][4*MAXN], node[15][4*MAXN];
LL pow_mod(LL a, LL b) {
if(b == 0) return 1;
LL ans = pow_mod(a, b/2);
ans = ans * ans % m;
if(b&1) ans = ans * a % m;
return ans;
}
void build(int o, int L, int R) {
for(int i = 0; i < p; i++) node[i][o] = 0, addv[i][o] = 0;
node[p][o] = addv[p][o] = 1;
if(L==R) {
int tmp = a[L];
for(int i = 0; i < p; i++) {
while(tmp%prime[i] == 0) {
tmp /= prime[i];
node[i][o]++;
addv[i][o]++;
}
}
node[p][o] = tmp;
addv[p][o] = tmp;
}
else {
int M = (L+R) >> 1;
build(2*o, L, M);
build(2*o+1, M+1, R);
for(int i = 0; i < p; i++) node[i][o] = node[i][o*2] + node[i][o*2+1];
node[p][o] = node[p][2*o] * node[p][2*o+1] % m;
}
}
void maintain(int o, int L, int R, int id) {
if(id != p) node[id][o] = 0;
else node[id][o] = 1;
if(R > L) {
int M = (L+R) >> 1;
if(id != p) node[id][o] = node[id][2*o] + node[id][2*o+1];
else node[id][o] = node[id][2*o]*node[id][2*o+1] % m;
}
if(id != p) node[id][o] += (R-L+1) * addv[id][o];
else node[id][o] = node[id][o] * pow_mod(addv[id][o], R-L+1) % m;
}
void update(int o, int L, int R, int y1, int y2, int id, int v) {
if(L>=y1 && R<=y2) {
if(id != p) addv[id][o] += v;
else addv[id][o] = addv[id][o] * v % m;
}
else {
int M = (L+R) >> 1;
if(y1 <= M) update(2*o, L, M, y1, y2, id, v);
if(y2 > M) update(2*o+1, M+1, R, y1, y2, id, v);
}
maintain(o, L, R, id);
}
LL query(int o, int L, int R, int y1, int y2, int add, int id) {
if(y1<=L && y2>=R) {
if(id != p) return node[id][o] + add * (R-L+1);
else return node[id][o] * pow_mod(add, R-L+1) % m;
}
else {
int M = (L+R) >> 1;
LL ans;
if(id != p) ans = 0;
else ans = 1;
if(y1 <= M) {
if(id != p) ans += query(2*o, L, M, y1, y2, add+addv[id][o], id);
else ans = ans * query(2*o, L, M, y1, y2, add*addv[id][o]%m, id) % m;
}
if(y2 > M) {
if(id != p) ans += query(2*o+1, M+1, R, y1, y2, add+addv[id][o], id);
else ans = ans * query(2*o+1, M+1, R, y1, y2, add*addv[id][o]%m, id) % m;
}
return ans;
}
}
int init_prime() {
int sz = 0;
int tmp = (int)sqrt(m+0.5), tm = m;
for(int i = 2; i <= tmp; i++) {
if(tm%i == 0) {
prime[sz++] = i;
while(tm % i == 0) tm /= i;
}
}
if(tm > 1) prime[sz++] = tm;
return sz;
}
void cal_modify(int v) {
memset(modify, 0, sizeof(modify));
modify[p] = 1;
for(int i = 0; i < p; i++) {
while(v%prime[i] == 0) {
v /= prime[i];
modify[i]++;
}
}
modify[p] = v;
}
void gcd(LL a, LL b, LL& d, LL& x, LL& y) {
if(!b){ d = a; x = 1; y = 0; }
else{ gcd(b, a%b, d, y, x); y -= x*(a/b); }
}
LL inv(LL a, LL n) {
LL d, x, y;
gcd(a, n, d, x, y);
return (x+n)%n;
}
int main() {
//freopen("input.txt", "r", stdin);
int T, kase = 0; cin >> T;
while(T--) {
scanf("%d%d", &n, &m);
p = init_prime();
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, 1, n);
printf("Case #%d:\n", ++kase);
scanf("%d", &Q);
char op[3];
for(int i = 1, l, r, v; i <= Q; i++) {
scanf("%s", op);
if(op[0] == 'Q') {
scanf("%d%d", &l, &r);
LL ans = 1;
for(int i = 0; i < p; i++) {
ans = ans * pow_mod(prime[i], query(1, 1, n, l, r, 0, i)) % m;
}
ans = ans * query(1, 1, n, l, r, 1, p) % m;
printf("%lld\n", ans);
}
else if(op[0] == 'M') {
scanf("%d%d%d", &l, &r, &v);
if(!v) {
update(1, 1, n, l, r, p, 0);
continue;
}
cal_modify(v);
for(int i = 0; i < p; i++) if(modify[i]) update(1, 1, n, l, r, i, modify[i]);
if(modify[p] > 1) update(1, 1, n, l, r, p, modify[p]);
}
else {
scanf("%d%d%d", &l, &r, &v);
cal_modify(v);
for(int i = 0; i < p; i++) if(modify[i]) update(1, 1, n, l, r, i, -modify[i]);
update(1, 1, n, l, r, p, inv(modify[p], m));
}
}
}
return 0;
}