开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情
【ICPC】2018南京站 J. Prime Game | 计数
题目链接
20182019-acmicpc-asia-nanjing-regional-contest-en.pdf (codeforces.com) Dashboard - 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest - Codeforces
题目
题目大意
给定 个正整数 。定义
定义 表示 中不同质因数的数量。
输出表达式
的值。
思路
显然可以对每个数字分解质因数,然后对其每个质因数单独进行统计这个质因数在多少个区间里有贡献。我们开一个数组 表示从开始遍历到当前位置,质数 最后一次出现在 里。
假设遍历到了位置 , 有质因数 ,我们知道 前面所有的下标中, 最后一个有质因数 的是 。为了避免重复计算,我们暂不考虑跨越了 的区间,只考虑不跨越 且跨越 的区间。这样的区间有 个,则我们认为 中 对答案的贡献为 。然后我们更新 。
等到遍历完整个数组后,我们对于每个 ,下标 对答案的贡献都还没有计算,则我们遍历 数组,每个 对答案的贡献为 。
代码
#include <stdio.h>
using namespace std;
using LL=long long;
const int N=1000001;
int n,a[N],vis[N],p[N],tot;
LL e[N];
int fc[N],m;
LL ans;
void split(int x)
{
m=0;
for (int i=1;i<=tot&&p[i]*p[i]<=x;++i)
{
if (x%p[i]) continue;
fc[++m]=p[i];
while (x%p[i]==0) x/=p[i];
}
if (x>1) fc[++m]=x;
}
int main()
{
n=1e6;
for (int i=2;i<=n;++i)
{
if (!vis[i]) p[++tot]=i;
for (int j=1;j<=tot&&i*p[j]<=n;++j)
{
vis[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
scanf("%d",&n);
for (int i=1,x;i<=n;++i)
{
scanf("%d",&x);
split(x);
for (int j=1;j<=m;++j)
{
if (e[fc[j]]) ans+=(i-e[fc[j]])*e[fc[j]];
e[fc[j]]=i;
}
}
for (int i=1;i<=1e6;++i)
if (e[i]) ans+=(n-e[i]+1)*e[i];
printf("%lld",ans);
return 0;
}