样例
10
99 62 10 47 53 9 83 33 15 24
248
10
6 7 5 5 4 9 9 1 8 12
134
题意
给你一个长度为n的序列
a
i
a_i
ai,定义
m
u
l
(
l
,
r
)
=
∑
i
=
l
r
a
i
mul(l,r)=\sum_{i=l}^ra_i
mul(l,r)=∑i=lrai,
f
a
c
(
l
,
r
)
fac(l,r)
fac(l,r)为
m
u
l
(
l
,
r
)
mul(l,r)
mul(l,r)的不同的素因子的个数,现在求解
∑
i
=
1
n
∑
j
=
i
n
f
a
c
(
i
,
j
)
\sum_{i=1}^n\sum_{j=i}^nfac(i,j)
i=1∑nj=i∑nfac(i,j)
思路
这样的计数题要考虑一下每个质数的贡献,那么每个数的贡献是多少呢我们对第二个样例分析一下
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
6 | 7 | 5 | 5 | 4 | 9 | 9 | 1 | 8 | 12 |
2,3 | 7 | 5 | 5 | 2 | 3 | 3 | 1 | 2 | 2,3 |
我们先考虑一下第一个2对答案的贡献,只有i=1的时候,第一个2
才有贡献,贡献的次数是
1
∼
1
1\sim1
1∼1,
1
∼
2
1\sim2
1∼2,
⋯
\cdots
⋯,
1
∼
10
1\sim 10
1∼10,一共贡献了十次,也就是第一个位置的2贡献值为10,同样的这个3也为10
那么我们现在的答案就是10+10了,然后我们考虑一下第二个位置的7
在i=1 的时候,这个7是在
1
∼
2
1\sim2
1∼2开始有贡献的也就是
1
∼
2
1\sim2
1∼2,
⋯
\cdots
⋯,
1
∼
10
1\sim 10
1∼10贡献了九次,然后当i=2的时候又有九次,所以这个7可以贡献2x9次,同样的第三个位置的5的贡献在i=1,i=2,i=3的贡献都是8次也就3x8,那么现在的总贡献值就是10+10+9x2+8x3,然后是第四个位置上的5,由于这个5前面已经出现过5了,我们为了避免重复计算,我们认为的i=1,i=2,i=3时的5都是三号位置上的5贡献的,那这个5所能贡献的值就是当i=4时贡献了7次,当前答案就是10+10+9x2+8x3+7
然后我们看五号位置上的2,由于第一个位置上出现过了2,就是i=1的时候的2都是上一个2所贡献的,这个2所能提供的贡献就要从i=2开始算了,那么他的贡献就是6x4,下面的数也都这样处理我们的最后的答案就是
10+10+9x2+8x3+7+6x4+5x5+4+0+2x4+1+3=134
那么只用预处理一遍质因子然后把质因子的位置存在vector里面然后只用扫一遍就知道答案了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <stack>
#include <list>
#include <unordered_map>
#define MAX 1000005//求MAX范围内的素数
using namespace std;
const int N=1e6+5;
long long su[MAX],cnt;
bool isprime[MAX];
void prime()
{
cnt=1;
memset(isprime,1,sizeof(isprime));//初始化认为所有数都为素数
isprime[0]=isprime[1]=0;//0和1不是素数
for(long long i=2; i<MAX; i++)
{
if(isprime[i])
su[cnt++]=i;//保存素数i
for(long long j=1; j<cnt&&su[j]*i<MAX; j++)
{
isprime[su[j]*i]=0;//筛掉小于等于i的素数和i的积构成的合数
}
}
}
int a[N];
vector<long long>mp[MAX];
void init(int x,int pos)
{
for(int i=1; su[i]*su[i]<=x; i++)
{
if(x%su[i]==0)
{
mp[su[i]].push_back(pos);
while(x%su[i]==0)
x/=su[i];
}
}
if(x>1)
{
mp[x].push_back(pos);
}
}
int main()
{
prime();
long long n;
while(scanf("%lld",&n)!=EOF)
{
for(int i=1;i<cnt;i++)
mp[su[i]].clear();
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
init(a[i],i);
}
long long ans=0;
for(int i=1; i<cnt; i++)
{
if(mp[su[i]].size()==0)
continue;
else
{
ans+=mp[su[i]][0]*(n-mp[su[i]][0]+1);
for(int j=1; j<mp[su[i]].size(); j++)
ans+=(mp[su[i]][j]-mp[su[i]][j-1])*(n-mp[su[i]][j]+1);
}
}
printf("%lld\n",ans);
}
return 0;
}