3.平方差 - 蓝桥云课
一开始看题我还没有意识到问题的严重性
我丢,我想 的是用两层循环来做,后来我试了一下最坏情况,也就是l=1 r = 1000000000
结果运行半天没运行出来,我就知道坏了,孩子们,要出事,结果又试了一下l = 1 r=1000
结果很快就出来了,我把r改成了10000 也出来了,改成1000000的时候就半天也算不出来,超级超时
package xunhuan;
import java.util.Map;
import java.util.Scanner;
/**
* @author zb
* date2025/3/17 15:57
*/
public class L3502 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int l = in.nextInt();
int r = in.nextInt();
// 统计满足条件的个数
int cnt =0 ;
// ijk分别代表三个数xyz
for (int i = 0; i <=r ; i++) {
for (int j = i; j <=r ; j++) {
long sum = (long) (j-i)*(j+i);
// 如果这个差值在l r的范围内就++
if(sum>=l&&sum<=r){
// System.out.println(i);
// System.out.println(j);
cnt++;
}
}
}
System.out.println(cnt);
in.close();;
}
}
奇怪的是一个点没有通过,真的有点奇怪呀,去看一下解析,我丢
去b站看了一下[蓝桥杯]真题讲解:平方差 (打表+数学)_哔哩哔哩_bilibili这个视频
我丢,我没有意识到 如果输入的数据1e9 意味着即使输出的复杂度为o(n也会超时)
所以要么用O(logn)复杂度输出要么用O(1)复杂度来解决,
O(1)的复杂度只能是你找到数学规律,也就是直接套公式得出答案
而O(logn)的话就只能通过降低复杂度来实现
这道题考察的是数学,直接枚举找规律,也叫打表
就是我先计算100以内的等于两个数的平方差的数有那些,下面用Java来实现
利用treeMap来实现便利100以内的等于两数平方差的数有那些,然后总结规律
package xunhuan;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
/**
* @author zb
* date2025/3/17 15:57
*/
public class L3502 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// int l = in.nextInt();
// int r = in.nextInt();
// 统计满足条件的个数
int cnt =0 ;
Map<Integer,Integer> mp = new TreeMap<>();
// ijk分别代表三个数xyz
for (int i = 1; i <=100 ; i++) {
for (int j = 0; j <=100 ; j++) {
int sum = i*i - j* j;
// 如果这个差值在l r的范围内就++
for (int k = 0; k <=100 ; k++) {
if(sum==k){
// if(k%2==0){
mp.put(k,0);
// }
// if(mp){
//
// System.out.println(sum);
// }
}
}
}
}
for (int key :mp.keySet()) {
System.out.println(key);
}
// System.out.println(cnt);
in.close();;
}
}
得到之后,我们发现,欸,好像奇数全都是,再看一下偶数,看偶数的话就把这里的注释去掉就行
偶数如图所示
你发现了什么是不是每一个偶数都是4的倍数(包括0)
你要是不信的话再试一下奇数如图所示
所以我们可以得出范围[l,r]之内的所有的奇数和4的倍数都是满足条件的
我们总结一下
区间【1,r】的奇数个数和偶数个数,因为l,r>=1
奇数:比如【1,3】 奇数 1 3 两个
【1,2】奇数个数1, 一个
是不是恰好等于(1+r)/2 不信的话再试一下
这里也可以理解为上取整
偶数个数的话:
【1,7】是不是只有一个数 是4
所以偶数个数是r/4
[1,r]的满足条件的个数为(r/4+(1+r)/2)
区间【1,l-1】的话是不是也是同理 ,奇数的个数直接把r换成l就行了4 的倍数不能动
【1,l-1】中满足条件的个数为((l)/4+(1+l-1)/2)
那么区间【l,r】之间的满足条件的个数是不是就等于区间【1,r】上面满足条件的个数减去【1,l-1】区间满足条件的个数
ok话不多上,我们直接整活儿
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
/**
* @author zb
* date2025/3/17 15:57
*/
public class Main {
public static void main(String[] args) {
Scanner in =new Scanner(System.in);
int l = in.nextInt();
int r = in.nextInt();
// [1,r]之间的等于平方差的数字的个数 -[1,l-1]之间的等于平方差的数字的个数
int sum = (1+r)/2+r/4 -((l)/2+l/4);
System.out.println(sum);
in.close();
}
}
不好,孩子们,有一个点没过,不知道为啥
弄明白了
因为我们要求的是[1,l-1]之间的满足条件的偶数数量 应该是(l-1)/4而不是l/4
改不对了,我快疯了,啊啊啊啊
不是我想不明白为啥要改成long 啊,10的9次方int接收不了吗好逆天呀,这道题,我快疯了
package xunhuan;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
/**
* @author zb
* date2025/3/17 15:57
*/
public class L3502 {
public static void main(String[] args) {
Scanner in =new Scanner(System.in);
Long l = in.nextLong();
Long r = in.nextLong();
// [1,r]之间的等于平方差的数字的个数 -[1,l-1]之间的等于平方差的数字的个数
Long num1 = (1+r)/2 -l/2;
Long num2 = r/4 - (l-1)/4 ;
System.out.println(num1+num2);
in.close();
}
}
整了我快3个小时了
在 Java 中,int
类型的最大值是 2^31-1 = 2,147,483,647
。当输入的 R
接近或超过 1e9
时,虽然 R
本身小于 int
的最大值,但中间运算可能导致溢出。以下是关键分析:
1. 当 R
接近 int
最大值时的溢出问题
假设 R = 2,147,483,647
(即 int
的最大值):
int R = 2_147_483_647;
int term = (R + 1) / 2; // R+1 = -2,147,483,648(溢出为负数)
2. 中间运算的溢出风险
在计算奇数的公式 (R + 1) / 2 - L / 2
中:
- 如果
R
接近int
最大值,R + 1
会溢出到负数范围。 - 例如:
int R = 1_500_000_000; // 1.5e9
int term = (R + 1) / 2; // 750,000,000.5 → 取整为 750,000,000
3. 为何输入范围是 1e9
时仍可能出错?
题目规定输入 L
和 R
的范围是 [1, 1e9]
,而 1e9
远小于 int
的最大值 2,147,483,647
。因此,理论上 int
足够存储输入值。但若代码中有其他操作(如中间运算或错误处理),可能导致意外溢出。
5. 总结
数据类型 | 优点 | 缺点 |
---|---|---|
int | 节省内存 | 中间运算可能溢出 |
long | 避免溢出 | 内存占用略高 |
- 推荐使用
long
:虽然题目输入范围在int
内,但使用long
更安全,避免潜在边界问题。 - 关键原则:在涉及大数运算时,优先使用
long
或BigInteger
。