题意
你有一个数组 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an。
现在你需要完成 q q q次操作,有以下两种操作形式:
-
MULTIPLY l r x
,对于所有 i ( l ≤ i ≤ r ) i(l\le i\le r) i(l≤i≤r),将 a i a_i ai乘上 x x x。 -
TOTIENT l r
,求出 φ ( ∏ i = l r a i ) \varphi(\prod_{i=l}^ra_i) φ(∏i=lrai),对 1 0 9 + 7 10^9+7 109+7取模后的结果。其中 φ \varphi φ表示欧拉函数, φ ( n ) \varphi(n) φ(n)的定义为 1 … n 1\dots n 1…n中与 n n n互质的数的个数。
时间限制
5.50s
内存限制
250.00MB
思路
对于某个数的欧拉函数,可以通过质因数分解求解,若
a
=
∑
i
p
i
α
i
a = \sum_ip_i^{\alpha_i}
a=∑ipiαi,那么
φ
(
a
)
=
a
∏
i
p
i
−
1
p
i
\varphi(a) = a\prod_i\frac{p_i - 1}{p_i}
φ(a)=a∏ipipi−1。
同时,观察到每个数的大小只有300,通过猜想与打表验证之后发现300以内的质数只有62个,那么可以把是否包含这些素数用
l
o
n
g
l
o
n
g
long\ long
long long状压起来。用线段树维护每一个区间所有数的乘积极其包含的质因数即可。
维护每个区间数的乘积就是维护乘法而已,非常简单。
维护每个区间数的乘积包含的质因数,由于状压起来了,那么两个子区间的状态进行或运算就可以。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <cmath>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 400005, mod = 1000000007;
int n, m;
int a[N];
int p[305];
bool vis[305];
struct Tree
{
int l, r;
LL pstate; int mul;
LL plz; int mullz;
}t[N << 2];
void get_prime(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!vis[i]) p[++ p[0]] = i;
for (int j = 1; j <= p[0] && i * p[j] <= n; j ++ )
{
vis[i * p[j]] = true;
if (i % p[j] == 0) break;
}
}
}
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1LL * res * a % mod;
b >>= 1;
a = 1LL * a * a % mod;
}
return res;
}
void push_up(int i)
{
t[i].mul = 1LL * t[i << 1].mul * t[i << 1 | 1].mul % mod;
t[i].pstate = t[i << 1].pstate | t[i << 1 | 1].pstate;
}
void calc(int i, int mul, LL state)
{
t[i].mul = 1LL * t[i].mul * qpow(mul, t[i].r - t[i].l + 1) % mod;
t[i].pstate |= state;
t[i].mullz = 1LL * t[i].mullz * mul % mod;
t[i].plz |= state;
}
void push_down(int i)
{
if (!t[i].plz) return;
int mul = t[i].mullz;
LL state = t[i].plz;
calc(i << 1, mul, state);
calc(i << 1 | 1, mul, state);
t[i].plz = 0, t[i].mullz = 1;
}
void build(int i, int l, int r)
{
t[i].l = l, t[i].r = r;
t[i].mul = 1, t[i].mullz = 1;
if (l == r)
{
int x = a[l];
t[i].mul = x;
for (int j = 1; j <= p[0]; j ++ )
if (x % p[j] == 0)
t[i].pstate |= 1LL << (j - 1);
return;
}
int mid = (l + r) >> 1;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
push_up(i);
}
void update(int i, int l, int r, int x, LL xp)
{
if (l <= t[i].l && t[i].r <= r)
{
calc(i, x, xp);
return;
}
push_down(i);
int mid = (t[i].l + t[i].r) >> 1;
if (l <= mid) update(i << 1, l, r, x, xp);
if (r > mid) update(i << 1 | 1, l, r, x, xp);
push_up(i);
}
pair<LL, int> query(int i, int l, int r)
{
if (l <= t[i].l && t[i].r <= r)
{
pair<LL, int> tt = make_pair(t[i].pstate, t[i].mul);
return tt;
}
push_down(i);
int mid = (t[i].l + t[i].r) >> 1;
if (l > mid) return query(i << 1 | 1, l, r);
else if (r <= mid) return query(i << 1, l, r);
else
{
pair<LL, int> ls = query(i << 1, l, r);
pair<LL, int> rs = query(i << 1 | 1, l, r);
ls.first |= rs.first;
ls.second = 1LL * ls.second * rs.second % mod;
return ls;
}
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
get_prime(300);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
scanf("%d", &a[i]);
build(1, 1, n);
for (int i = 1; i <= m; i ++ )
{
char s[10];
scanf("%s", s);
if (s[0] == 'T')
{
int l, r;
scanf("%d%d", &l, &r);
pair<LL, int> t = query(1, l, r);
int ans = t.second;
LL pstate = t.first;
for (int j = 1; j <= p[0]; j ++ )
if (pstate & (1LL << (j - 1)))
ans = 1LL * ans * (p[j] - 1) % mod * qpow(p[j], mod - 2) % mod;
printf("%d\n", ans);
}
else
{
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
LL xp = 0;
for (int j = 1; j <= p[0]; j ++ )
if (x % p[j] == 0)
xp += (1LL << (j - 1));
update(1, l, r, x, xp);
}
}
return 0;
}