小蓝发现了一个有趣的数列,这个数列的前几项如下:
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 ≤ 106。
对于 70% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 109。
对于 80% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 1012。
对于 90% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 1012。
对于所有评测用例,1 ≤ T ≤ 100000, 1 ≤ li ≤ ri ≤ 1012。
本题思路
主要思路是二分+计算公式
首先我们来推计算公式,本题相对放宽我们只需要知道在这一行内的和即可也就是
(首项+末项)*项数/2
然后我们进行累加即可求出前n行和
那么这题我们思路就很明确了,用j项和-i项和就可以得出范围内的和
那么现在问题就是集中于如何求出j项和,这里基本思路是找到j所在的行,j-1项直接得,然后再加上这一行的首项到j项即可
如何求所在的行呢?
这边用到二分,首先我们先建一个数组,在这个数组里存放第几行的最后一个是第几项,然后通过二分查找如果这个所寻找的项数所在的行就可以啦
那么到这里就差不多,然后还有一个问题数组开多大
这边推荐一个博文:蓝桥杯 国赛题——123 java_Break;的博客-CSDN博客_蓝桥杯国赛题目
这篇博文讲的不错
然后上代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main123 {
static long aa[]=new long[1414220],bb[]=new long[1414220];
public static void main(String[] args) throws IOException {
StreamTokenizer x=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out=new PrintWriter(System.out);
x.nextToken();
int n=(int)x.nval;
init();//初始化,千万别忘!!!
while(n--!=0) {
x.nextToken();
long i=(long)x.nval;
x.nextToken();
long j=(long)x.nval;
out.println(get(j)-get(i-1));
}
out.flush();
}
public static void init() {
for (int i = 1,p=1; i < aa.length; i++,p++) {
aa[i]=aa[i-1]+p;//存放每一行最后一项的项数
bb[i]=bb[i-1]+sum(i);//得出第i行的和
}
}
public static long get(long l) {
if(l==0)
return l;
int p=check(l);//二分查出前一行是第几行
long q=l-aa[p];//得出现在处在这行的第几项
return sum(q)+bb[p];//然后算出这一行,然后加上前一行和
}
public static int check(long k) {
int l=0,r=1414219;
while(l<=r) {
int mod=(l+r)/2;
if(aa[mod]<k)
l=mod+1;
else
r=mod-1;
}
return l-1;
}
public static long sum(long i) {
return i*(i+1)/2;//公式求和
}
}