【蓝桥】决赛 【123】

本文介绍了如何解决一个涉及数列求和的问题,该问题要求计算特定范围内数列的总和。主要思路是利用二分查找确定数列中某项的位置,并结合等差数列求和公式快速计算连续段的和。给出的代码示例展示了如何实现这个算法,包括初始化、二分查找和求和函数的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小蓝发现了一个有趣的数列,这个数列的前几项如下:
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;//公式求和
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值