思路:
博客:https://www.cnblogs.com/dilthey/p/9985010.html
考虑每个质因子对于整体答案的贡献。
拿第二组样例算一算就不难发现:第 pp 个位置上的数,其包含的任意一个素因子,它原本应当产生的贡献有 (n−p+1)⋅p(n−p+1)⋅p,
但是考虑到若其前面出现过一样的素数,那么应当减去一些重复计算的区间。假设它前面的和它一样的素数,最后一次出现在 qq 位置,那么就应当减去 (n−p+1)⋅q(n−p+1)⋅q,即 a[p]a[p] 包含的任意一个质因子其产生的贡献为 (n−p+1)⋅p−(n−p+1)⋅q=(n−p+1)⋅(p−q)(n−p+1)⋅p−(n−p+1)⋅q=(n−p+1)⋅(p−q)。
不妨用 pos[i][k]pos[i][k] 来存储每个素因子的 “pp”,pos[i][k−1]pos[i][k−1] 存储每个素因子的 “qq”。换句话说,pos[i][k]pos[i][k] 代表某个素因子 ii 在 a[1∼n]a[1∼n] 中第 kk 次“出现”的位置是 pos[i][k]pos[i][k];特别地,令 pos[i][0]=0pos[i][0]=0。那么对于任意素因子 ii,它对答案的贡献是 (n−pos[i][k]+1)⋅(pos[i][k]−pos[i][k−1])(n−pos[i][k]+1)⋅(pos[i][k]−pos[i][k−1])。
我们可以对 a[1∼n]a[1∼n] 分解质因数,然后更新相应的 pos[i][k]pos[i][k]。
Code:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int,int> pr;
const int MAX_S=1e6+5;
int n;
int prime[MAX_S];
int visit[MAX_S];
vector<LL> ive[MAX_S];
void Find(int t,int x);
void Prime_euler(int maxn);
int main()
{
ios::sync_with_stdio(false);
Prime_euler(MAX_S-2);
cin>>n;
for(int i=1;i<=prime[0];++i)
ive[prime[i]].push_back(0);
for(int i=1,x;i<=n;++i)
{
cin>>x;
Find(i,x);
}
int si;
LL res=0;
for(int i=1;i<=prime[0];++i)
{
si=ive[prime[i]].size();
for(int j=1;j<si;++j)
res+=(ive[prime[i]][j]-ive[prime[i]][j-1])*(n-ive[prime[i]][j]+1);
}
cout<<res<<endl;
return 0;
}
void Find(int t,int x){
for(int i=1;i<=prime[0]&&prime[i]*prime[i]<=x;++i)
{
if(x%prime[i]==0){
ive[prime[i]].push_back(t);
while(x&&x%prime[i]==0){
x/=prime[i];
}
}
}
if(x) ive[x].push_back(t);
}
void Prime_euler(int n)
{
for(int i=2;i<=n;++i)
{
if(!visit[i]) prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
{
visit[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}