数论 + 单调栈
没错吧又是区间问题,而且是一个很恶心的区间问题。赶紧去宰了出题人
-
首先需要明白任何一个数字 x x x 都可以写成 x = p 1 a 1 × p 2 a 2 × p 3 a 3 × ⋯ × p m a m x = p_{1}^{a_{1}} \times p_{2}^{a_{2}} \times p_{3}^{a_{3}} \times \dots \times p_{m}^{a_{m}} x=p1a1×p2a2×p3a3×⋯×pmam 。其中 p 1 ∼ p m p_{1} \sim p_{m} p1∼pm 都是质数。 a 1 ∼ a m a_{1} \sim a_{m} a1∼am 都是对应的质数。
-
对于一个拥有 n n n 个数字的数组 x x x ,那么有
-
g c d i = 1 n x i = p 1 m i n i = 1 n a 1 , x i × p 2 m i n i = 1 n a 2 , x i × p 3 m i n i = 1 n a 3 , x i × ⋯ × p m m i n i = 1 n a m , x i gcd_{i = 1}^{n}{x_{i}} = p_{1}^{min_{i = 1}^{n}a_{1, x_{i}}} \times p_{2}^{min_{i = 1}^{n}a_{2, x_{i}}} \times p_{3}^{min_{i = 1}^{n}a_{3, x_{i}}} \times \dots \times p_{m}^{min_{i = 1}^{n}a_{m, x_{i}}} gcdi=1nxi=p1mini=1na1,xi×p2mini=1na2,xi×p3mini=1na3,xi×⋯×pmmini=1nam,xi 其中 p 1 ∼ p m p_{1} \sim p_{m} p1∼pm 表示的是数字 x 1 ∼ x n x_{1} \sim x_{n} x1∼xn 都有的质数; a i , x j a_{i, x_{j}} ai,xj 表示的是数字 x j x_{j} xj 对应的第 i i i 个质数。 m i n i = 1 n a 1 , x i min_{i = 1}^{n}a_{1, x_{i}} mini=1na1,xi 表示的是对于这 n n n 个数字第一个质数的质数的最小值。
-
l c m i = 1 n x i = p 1 m a x i = 1 n a 1 , x i × p 2 m a x i = 1 n a 2 , x i × p 3 m a x i = 1 n a 3 , x i × ⋯ × p m m a x i = 1 n a m , x i lcm_{i = 1}^{n}{x_{i}} = p_{1}^{max_{i = 1}^{n}a_{1, x_{i}}} \times p_{2}^{max_{i = 1}^{n}a_{2, x_{i}}} \times p_{3}^{max_{i = 1}^{n}a_{3, x_{i}}} \times \dots \times p_{m}^{max_{i = 1}^{n}a_{m, x_{i}}} lcmi=1nxi=p1maxi=1na1,xi×p2maxi=1na2,xi×p3maxi=1na3,xi×⋯×pmmaxi=1nam,xi 其中 p 1 ∼ p m p_{1} \sim p_{m} p1∼pm 表示的是数字 x 1 ∼ x n x_{1} \sim x_{n} x1∼xn 都有的质数; a i , x j a_{i, x_{j}} ai,xj 表示的是数字 x j x_{j} xj 对应的第 i i i 个质数。 m a x i = 1 n a 1 , x i max_{i = 1}^{n}a_{1, x_{i}} maxi=1na1,xi 表示的是对于这 n n n 个数字第一个质数的质数的最大值。
-
知道上述结论了之后,现在需要求解的是指数之和,因此可以枚举不同的质数,针对于每一个质数进行答案的求解。
-
设 n u m s [ i ] nums[i] nums[i] 表示对于第 i i i 个数字,质数 p r [ j ] pr[j] pr[j] 出现的次数。因此这里可以直接枚举右端点。以最大公约数为例,针对于新进来的第 i i i 个数字,他在区间中,那么就需要考虑当前质数他的指数对最小值的影响。要计算第 i i i 个数字的影响就需要知道前面的最小值、次小值、次次小值等等。因此这里可以使用单调栈来维护,在求解最大公约数的时候栈内维护的是一个单增的序列,只要 n u m s [ i ] nums[i] nums[i] 比栈顶元素大,那么就出栈栈顶元素。因为在枚举栈内元素的时候计算了他们对答案的贡献,因此这里出栈需要把贡献减去。
-
最小公倍数和最大公约数的情况类似。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int mod = 1e9 + 7;
const int N = 10010, M = 50010;
int n;
int a[N];
int nums[N];
int idx, pr[M];
bool is_de[M];
void init(int n) {
for (int i = 2; i <= n; i ++ ) {
if (!is_de[i]) pr[ ++ idx] = i;
is_de[i] = true;
for (int j = 1; pr[j] <= n / i; j ++ ) {
is_de[pr[j] * i] = true;
if (i % pr[j] == 0) break;
}
}
}
long long get() {
long long res = 0, sum = 0;
stack<pair<int, int>> stk;
for (int i = 1; i <= n; i ++ ) {
while (!stk.empty() && nums[stk.top().first] <= nums[i]) {
sum -= stk.top().second;
stk.pop();
}
if (stk.empty()) {
sum += nums[i] * i;
stk.emplace(i, nums[i] * i);
} else {
sum += nums[i] * (i - stk.top().first);
stk.emplace(i, nums[i] * (i - stk.top().first));
}
res = (res + sum) % mod;
}
sum = 0;
stk = stack<pair<int, int>>();
for (int i = 1; i <= n; i ++ ) {
while (!stk.empty() && nums[stk.top().first] >= nums[i]) {
sum += stk.top().second;
stk.pop();
}
if (stk.empty()) {
sum -= nums[i] * i;
stk.emplace(i, nums[i] * i);
} else {
sum -= nums[i] * (i - stk.top().first);
stk.emplace(i, nums[i] * (i - stk.top().first));
}
res = (res + sum) % mod;
}
return res;
}
void solve() {
init(M - 1);
cin >> n;
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
}
long long res = 0;
for (int i = 1; i <= idx; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
nums[j] = 0;
while (a[j] % pr[i] == 0) nums[j] ++ , a[j] /= pr[i];
}
res = (res + get()) % mod;
}
cout << res << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
// cin >> T;
while (T--) {
solve();
}
return 0;
}