题目大意:
题目链接:
洛谷:https://www.luogu.org/problemnew/show/P2261
JZOJ:https://jzoj.net/senior/#main/show/3912
给定
x
,
y
x,y
x,y,求
∑
i
=
1
y
x
%
i
\sum^{y}_{i=1}x\%i
i=1∑yx%i
思路:
首先暴力打个表。
1- 0
2- 0 0
3- 0 1 0
4- 0 0 1 0
5- 0 1 2 1 0
6- 0 0 0 2 1 0
7- 0 1 1 3 2 1 0
8- 0 0 2 0 3 2 1 0
9- 0 1 0 1 4 3 2 1 0
10- 0 0 1 2 0 4 3 2 1 0
11- 0 1 2 3 1 5 4 3 2 1 0
12- 0 0 0 0 2 0 5 4 3 2 1 0
13- 0 1 1 1 3 1 6 5 4 3 2 1 0
14- 0 0 2 2 4 2 0 6 5 4 3 2 1 0
15- 0 1 0 3 0 3 1 7 6 5 4 3 2 1 0
16- 0 0 1 0 1 4 2 0 7 6 5 4 3 2 1 0
17- 0 1 2 1 2 5 3 1 8 7 6 5 4 3 2 1 0
18- 0 0 0 2 3 0 4 2 0 8 7 6 5 4 3 2 1 0
19- 0 1 1 3 4 1 5 3 1 9 8 7 6 5 4 3 2 1 0
20- 0 0 2 0 0 2 6 4 2 0 9 8 7 6 5 4 3 2 1 0
21- 0 1 0 1 1 3 0 5 3 1 10 9 8 7 6 5 4 3 2 1 0
22- 0 0 1 2 2 4 1 6 4 2 0 10 9 8 7 6 5 4 3 2 1 0
23- 0 1 2 3 3 5 2 7 5 3 1 11 10 9 8 7 6 5 4 3 2 1 0
24- 0 0 0 0 4 0 3 0 6 4 2 0 11 10 9 8 7 6 5 4 3 2 1 0
25- 0 1 1 1 0 1 4 1 7 5 3 1 12 11 10 9 8 7 6 5 4 3 2 1 0
26- 0 0 2 2 1 2 5 2 8 6 4 2 0 12 11 10 9 8 7 6 5 4 3 2 1 0
27- 0 1 0 3 2 3 6 3 0 7 5 3 1 13 12 11 10 9 8 7 6 5 4 3 2 1 0
28- 0 0 1 0 3 4 0 4 1 8 6 4 2 0 13 12 11 10 9 8 7 6 5 4 3 2 1 0
29- 0 1 2 1 4 5 1 5 2 9 7 5 3 1 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
30- 0 0 0 2 0 0 2 6 3 0 8 6 4 2 0 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
第
i
i
i行的第
j
j
j个数字表示
x
=
i
,
y
=
j
x=i,y=j
x=i,y=j时的答案。(第一列是行标号)。
然后就会发现:
当
l
=
[
x
÷
i
]
,
r
=
[
x
÷
(
i
+
1
)
]
l=[x\div i],r=[x\div (i+1)]
l=[x÷i],r=[x÷(i+1)]时,
l
∼
r
l\sim r
l∼r之间的所有数字被
x
x
x除之后的余数是一个公差为
i
i
i的等比数列。(
[
]
[]
[]表示向下取整)
那么可以枚举
i
i
i,求出
l
,
r
l,r
l,r,然后求出项数,最后用等差数列求和公式即可。
但是当
x
=
y
=
1
0
9
x=y=10^9
x=y=109时,需要枚举
1
0
9
10^9
109次,会稳稳超时。
所以当
[
x
÷
i
]
=
[
x
÷
(
i
+
1
)
]
[x\div i]=[x\div (i+1)]
[x÷i]=[x÷(i+1)]时,剩余的数字在
n
\sqrt{n}
n左右,直接推出枚举暴力求解即可。
然后就愉快的拿到
80
80
80分。
注意题目没说
y
≤
x
y\leq x
y≤x,所以当
y
>
x
y>x
y>x时,直接
if (m>n)
{
ans+=(m-n)*n;
m=n;
}
时间复杂度: O ( O( O(玄学 ) ) ),大约 O ( x ) O(\sqrt{x}) O(x)吧。
代码:
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
ll n,m,ans,a1,an,s,k;
int main()
{
cin>>n>>m;
if (m>n)
{
ans+=(m-n)*n;
m=n;
}
for (ll i=n/m;(n/i)!=(n/(i+1));i++) //枚举i,判断[x/i]和[x/(i+1)]
{
a1=n%min(n/i,m); //首项
an=n%(n/(i+1)+1); //末项
ans+=(a1+an)*(an-a1+i)/i/2; //求和公式
k=n/(i+1)+1; //记录计算到那个位置
}
for (ll i=1;i<k;i++) //剩余暴力求解
ans+=n%i;
cout<<ans<<endl;
return 0;
}