一、题目
二、解法分析
我用的方法是前缀和+二分。创建一个vector,用来记录数量的前缀和,例如0、1、3、6、10。再创建一个map,用来记录对应于每一个数量的前缀和,例如对应上面的,那就是0、1、4、10、20。(即0、0+1、0+1+1+2、0+1+1+2+1+2+3、0+1+1+2+1+2+3+1+2+3+4)。用题目所给的范围把map和vector初始化好之后,就可以进行t次的查询了。我的方法是这样:举个例子,题目某次查询为5、8,那么我们通过lower_bound找到vector中大于等于5的第一个数,即6;再通过同样的方式找到vector中大于等于8的第一个数,即10。然后为了求出5~8的区间和,我将10的前一个数(即6)的前缀和(即10)减去6的前一个数(即3)的前缀和(即4),然后减去(5-3-1)(1+5-3-1)/2,再加上(8-6)(1+8-6)/2。得出结果为10-4-1+3=8。下面这张图能很好得解释这种做法。
三、代码
#include <bits/stdc++.h>
using namespace std;
int t;
long long sumed=0;
long long sum2;
map<long long,long long>a;
vector<long long>b;
int main()
{
long long l;
long long r;
long long i=1;
long long sum=0;
b.push_back(0);
a[0]=0;
while(1)
{
if(sumed>=1000200000000)
{
break;
}
sumed=sumed+i;
b.push_back(sumed);
// printf("%lld\n",sumed);
sum=sum+(1+i)*i/2;
a[sumed]=sum;
// printf("%lld\n",sum);
i++;
}
cin>>t;
while(t--)
{
cin>>l;
cin>>r;
int s1=lower_bound(b.begin(),b.end(),l)-b.begin();
int s2=lower_bound(b.begin(),b.end(),r)-b.begin();
sum2=a[b[s2-1]]-a[b[s1-1]];
long long c1=(l-b[s1-1]-1)*(1+l-b[s1-1]-1)/2;
long long c2=(r-b[s2-1])*(1+r-b[s2-1])/2;
sum2=sum2-c1+c2;
printf("%lld\n",sum2);
}
return 0;
}