小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少?
输入格式
输入的第一行包含一个整数 T,表示询问的个数。
接下来 T 行,每行包含一组询问,其中第 i 行包含两个整数 li 和 ri,表示询问数列中第 li 个数到第 ri 个数的和。
输出格式
输出 T 行,每行包含一个整数表示对应询问的答案。
样例输入
3
1 1
1 3
5 8
样例输出
1
4
8
评测用例规模与约定
对于 10% 的评测用例, 1 ≤ T ≤ 30, 1 ≤ li ≤ ri ≤ 100。
对于 20% 的评测用例, 1 ≤ T ≤ 100, 1 ≤ li ≤ ri ≤ 1000。
对于 40% 的评测用例, 1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10 ^ 6。
对于 70% 的评测用例, 1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10 ^ 9。
对于 80% 的评测用例, 1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10 ^ 12。
对于 90% 的评测用例, 1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10 ^ 12。
对于所有评测用例, 1 ≤ T ≤ 100000, 1 ≤ li ≤ ri ≤ 10 ^ 12。
题解:
利用二分的思想(但是这个二分的上界MAX不知道怎么确定,我是加0减0试出来的,太大了会越界)先查找到li所在的区间,再在li的基础上暴力找到ri的区间(能不能再用一次二分找到ri的区间呢,可以一试),过了80%的测试用例,剩余20%超时,时间复杂度还有待优化。(5.11版本v1.0,希望有生之年能优化它)
#include <stdio.h>
#include <stdlib.h>
#define MAX 10000000 //试出来的,太大会越界
long long leijia(long long x, long long y)
{
long long a = y-x+1;
if(a%2==0) //a是偶数
{
return (x+y)*(a/2);
}
else //a是奇数
{
return (x+y)*(a/2)+((x+y)/2); //修改2:a/2-1改成(x+y)/2
}
}
long long binary_search(long long x, long long y)
{
long long low = 1;
long long high = MAX;
while(low <= high)
{
long long mid = (low+high)/2;
long long left = leijia(1,mid-1);
long long right = leijia(1,mid);
if(x > left && x <= right)
{
//x所在区间的大小为mid,还需判断y是和x在同一个区间,还是在其后的某个区间
long long num = y-x+1; //从x到y的元素个数
long long num1 = mid-(x-left)+1; //从x到区间mid末尾的元素个数
if(num <= num1) //y和x在同一个区间
{
return leijia(x-left,y-left);
}
else //y在mid其后的某个区间
{
long long sum=0;
long long i=1;
num -= num1;
sum += leijia(x-left,mid);
while(num-(mid+i)>=0) //判断y是否在mid+i区间内
{
sum += leijia(1,mid+i);
num -= mid+i; //修改1:1改成了i
i++;
}
sum += leijia(1,num);
return sum;
}
}
else if(x <= left)
{
high = mid-1;
}
else
{
low = mid+1;
}
}
}
int main(int argc, char *argv[])
{
int t;
scanf("%d",&t);
long long a[t][2];
long long res[t];
int i;
for(i=0;i<t;i++)
{
scanf("%lld %lld",&a[i][0],&a[i][1]);
}
for(i=0;i<t;i++)
{
res[i] = binary_search(a[i][0],a[i][1]);
}
for(i=0;i<t;i++)
{
printf("%lld\n",res[i]);
}
return 0;
}