Gym - 101981J 质因数分解 + 思维

需要存储每个质因数存在的位置,然后计算出每个质因数的贡献和。

题目链接

题意

Mul(i,j)代表的是第i到j个数字的乘积,然后fac(i,j)代表这个乘积的不同的质因子的个数。现在让你求出n^2段区间内的fac(i,j)和.

思路

显然不能用N^2的做法。我们可以先把每个数字质因数分解,存储每个质因数所在的位置。比如说序列为22,33。 那么11这个质因数存在的位置就是1,2. 然后我们枚举每个质因数的每个存在的位置,计算贡献和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string>
#include <cstring>
const int maxn = 1000000;
using namespace std;
typedef long long ll;
vector<int>V[maxn + 5];
int tot,a[maxn + 5];
bool is[maxn + 5];
int prime[maxn + 5],n;
void Prime()
{
memset(is, 0, sizeof(is));
for(int i = 2; i <= maxn; ++i)
{
if(!is[i])
{
prime[++tot] = i;
for(int j = i + i; j <= maxn; j += i)
{
is[j] = 1;
}
}
}
}

void solve()
{
for(int i = 1; i <= n; ++i){
for(int j = 1; prime[j] * prime[j] <= a[i] && j <= tot; ++j)
{
if(a[i] % prime[j] == 0)
{
V[prime[j]].push_back(i);
while(a[i] % prime[j] == 0)
a[i] /= prime[j];
}
}
if(a[i] != 1)
V[a[i]].push_back(i);
}
}
int main()
{
tot = 0;
Prime();
cin >> n;
for(int i = 1; i <= n; ++i)
scanf("%d",&a[i]);
solve();
ll ans = 0;
for(int i = 1; i < maxn; i ++)
{
if(V[i].size() == 0)continue;
for(int j = 0; j < V[i].size(); ++j)
{
if(j == 0)
ans += 1ll * (n - V[i][j] + 1) * (V[i][j]);
else
ans += 1ll *(n - V[i][j] + 1) * (V[i][j] - V[i][j - 1]);
}
}
cout << ans << '\n';
}