题意
题目意思就是每个子区间乘积总共有多少不同质因数。
分析
第 i 个数的质因数对总数的贡献就是 i * (n - i + 1) ,即这个数被包含在 i * (n - i + 1) 个子区间里。但是我们发现如果有两个数有同一个质因数,那么这种算法就会将一部分重复计算,于是我们可以用一个 pos 数组来记录某个质因数在前面最后出现的位置,那么公式就变成了 (i - pos[x]) * (n - i + 1) ,这样就能避免重复计算。
解决了重复计算的问题,接下来就只要解决质因数的问题就可以了。如何得到一个数的质因数?这里有一条重要的定理:每个整数都可以分解成几个素数的乘积。我们就可以先用素数筛筛选出题目数据范围内的所有素数,然后依次遍历,发现质因数就将其先除尽,如此往复,就能获得其所有质因数。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 1000007
ll n;
ll ans;
map<ll,ll> pos;
ll prime[maxn];
ll visit[maxn];
void Prime(){
for (ll i = 2;i <= maxn; i++) {
if (!visit[i]) {
prime[++prime[0]] = i;
}
for (ll j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
int main()
{
Prime();
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
ll x;
scanf("%lld",&x);
for(ll j=1;1ll*prime[j]*prime[j]<=x;j++)
{
if(x % prime[j] == 0)
{
ll temp = 1ll * (i - pos[prime[j]]) * (n - i + 1);
pos[prime[j]] = i;
ans += temp;
while(x % prime[j] == 0)
x /= prime[j];
}
}
if(x != 1)
{
ll temp = 1ll * (i - pos[x]) * (n - i + 1);
pos[x] = i;
ans += temp;
}
}
printf("%lld",ans);
return 0;
}