解题思路

对于1,2,3,4,5,6,…, n
我们用数组s_n表示前n项和,使用数组sum_n表示数组sn项和;
初始化:

  1. void init() {
  2. for (int i = 1; i < N; i++) {
  3. s[i] = s[i - 1] + i;
  4. sum[i] = sum[i - 1] + s[i];
  5. }
  6. }

每次查询 l 和 r 时,使用二分查找大于s_i的最小下标fl和fr;
二分查找:

  1. ll find(ll x) {
  2. ll l = 1, r = N - 5;
  3. ll mid;
  4. while (l <= r) {
  5. mid = l + ((r - l) >> 1);
  6. if (s[mid] >= x) r = mid - 1;
  7. else l = mid + 1;
  8. }
  9. return l;
  10. }

如上图所示:那么区间l到r的值即为:
sum[fr] - sum[fl - 1] - s[l - 1 - s[fl - 1]] - s[fr] + s[r - s[fr - 1]]

完整代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. const int N = 15e5 + 5;
  5. ll s[N];
  6. ll sum[N];
  7. void init() {
  8. for (int i = 1; i < N; i++) {
  9. s[i] = s[i - 1] + i;
  10. sum[i] = sum[i - 1] + s[i];
  11. }
  12. }
  13. ll find(ll x) {
  14. ll l = 1, r = N - 5;
  15. ll mid;
  16. while (l <= r) {
  17. mid = l + ((r - l) >> 1);
  18. if (s[mid] >= x) r = mid - 1;
  19. else l = mid + 1;
  20. }
  21. return l;
  22. }
  23. ll t, l, r;
  24. int main() {
  25. init();
  26. scanf("%lld", &t);
  27. while (t--) {
  28. scanf("%lld%lld", &l, &r);
  29. int fl = find(l);
  30. int fr = find(r);
  31. ll ans = sum[fr] - sum[fl - 1] - s[l - 1 - s[fl - 1]] - s[fr] + s[r - s[fr - 1]];
  32. printf("%lld\n", ans);
  33. }
  34. return 0;
  35. }
点赞(0)
 

9.9 分

6 人评分

 

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论