通过题目描述,我们知道如果单纯用暴力求前缀和肯定过不了大部分样例,我们通过观察可以将数列分为n行,每行都以1开头n结尾,我们可以发现前n行总共的数字数目可以用高斯求和来得出,这样我们可以通过二分查找出所在的行数,我们就直接定位到前1行,对于多出来的部分我们再额外加进去即可
上代码
#include<iostream>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
int pre(int n)
{
int l = 0, r = 1e5 + 10;
while(l < r){
int mid = (l + r) / 2;
if((mid + 1) * mid / 2 >= n) r = mid;//对于二分查找直接用高斯求和查找其所在的行号
else l = mid + 1;
}
int res = r - 1;//查找出n所在的行数,定位到前一行
int tmp = n - (res + 1) * res / 2;//查找多余出来的项数
int ans = 0;
ans = res * (res + 1) * (res + 2) / 6;//求出前r行的前缀和
ans = ans + (tmp + 1) * tmp / 2;//求出第n行中前tmp项的前缀和
return ans;
}
signed main(void)
{
int t; cin >> t;
while(t--){
int l, r; cin >> l >> r;
cout << pre(r) - pre(l - 1) << endl;//调用函数求前n项的前缀和
}
return 0;
}