题目链接
思路
一道蓝题,总不可能一个模拟就解决吧。看到数据范围,结合样例,便可知这道题一定是数学分析。具体来说,是一道整除分块题。(可以去科普一下,或者看下面的分析)
易得,
所以,原式可以转化为
接着观察样例:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
0 | 1 | 2 | 1 | 0 | 5 | 5 | 5 | 5 | 5 |
可以发现
的值都相等
(证明:
)
这样就把 n 个数分成了若干组,那时间复杂度是什么呢?
可以发现对于任意的 i , 的值至多由
段组成,
每一段中
的值都是
这一段的要计算的就是
这样就可以用等差数列求和公式计算,公差为
(首项 + 末项)* 项数 / 2
那么这一段时间复杂度就是 O(1)
整个程序的时间复杂度就是 O()
完整Code(非常简短)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, k, res;
int main()
{
cin >> n >> k;
res = n * k; // 先赋值为 n * k
// 再依次减去每一段的值
for (int front = 1, rear; front <= n; front = rear + 1)
{
// front 这一段的第一个
// rear 这一段的最后一个
rear = k / front ? min(k / (k / front), n) : n;
res -= (k / front * front + k / front * rear) * (rear - front + 1) / 2;
// (首项 + 末项) * 项数 / 2
// 也可以把 (k / front) 提出来
// res -= (k / front) * (front + rear) * (rear - front + 1) / 2;
}
cout << res << endl;
return 0;
}