题目传送门
[COCI2016-2017#6] Savrsen - 洛谷
1.题目大意
给你一个区间,问这个区间里每个数与它所有比它小的因数和的绝对值之和。
形象化地,如果给你区间
l
,
r
l,r
l,r ,并且记
x
x
x 所有比它小的因数依次为
p
x
,
1
,
p
x
,
2
,
⋅
⋅
⋅
,
p
x
,
k
x
p_{x,1},p_{x,2},···,p_{x,k_x}
px,1,px,2,⋅⋅⋅,px,kx ,那么答案为
∑
i
=
l
r
∣
∑
j
=
1
k
i
−
i
∣
\sum_{i=l}^r |\sum_{j=1}^{k_i} - i|
i=l∑r∣j=1∑ki−i∣
注:
l
,
r
<
1
0
7
l,r < 10^7
l,r<107
2.思路分析
首先考虑暴力,要枚举区间 l , r l,r l,r ,还要枚举每个数的因数和,记 n = r − l + 1 n = r-l+1 n=r−l+1 ,所以时间复杂度为 O ( n n ) O(n \sqrt n) O(nn)
思考如何简化题目描述中的式子。
我们发现,这个问题的瓶颈在于 n \sqrt n n 。我们可不可以提前预处理所有 i ≤ r i \leq r i≤r 的因数之和呢?
我们发现,埃氏筛可以完美的解决这个问题。
for (int i=1;i<=b;i++)
{
for (int j=2;j*i<=b;j++)
{
s[i*j] += i; //记录因数和
}
}
需要注意的是,由于我们需要枚举所有因数,而不是单纯的筛质数,所以内层要一直枚举到 r r r 。
这样,我们统计答案只需要计算: ∑ i = l r ∣ i − s i ∣ \sum_{i=l}^r |i-s_i| i=l∑r∣i−si∣
3.代码实现
这一题时间为 3 s 3s 3s ,常数上没问题可以通过。
#include <bits/stdc++.h>
using namespace std;
long long a,b,ans;
int s[10000005];
int main()
{
cin >> a >> b;
ans = 0;
for (int i=1;i<=b;i++)
{
for (int j=2;j*i<=b;j++)
{
s[i*j] += i;
}
}
for (int i=a;i<=b;i++)
{
ans += abs(i-s[i]);
}
cout<<ans<<endl;
}