2025A-数字加减游戏
题目描述与示例
题目描述
小明在玩一个数字加减游戏,只使用加法或者减法,将一个数字 s 变成数字 t。
每个回合,小明可以用当前的数字加上或减去一个数字。
现在有两种数字可以用来加减,分别为a,b(a != b),其中 b 没有使用次数限制。
请问小明最少可以用多少次 a,才能将数字 s 变成数字 t。
题目保证数字 s 一定能变成数字 t。
题目练习网址:https://www.algomooc.com/problem/P2498
输入描述
输入的唯一一行包含四个正整数 s,t,a,b(1 ≤ s,t,a,b ≤ 10^5),并且a != b。
输出描述
输出的唯一一行包含一个整数,表示最少需要使用多少次 a 才能将数字 s 变成数字 t
示例一
输入
1 10 5 2输出
1说明
初始值1加一次a变成6,然后加两次b变成10,因此a的使用次数为1
示例二
输入
11 33 4 10输出
2说明
11减两次a变成3,然后加三次b变成33,因此a的使用次数为2次
解题思路
首先理解题意,b的使用次数的无限的,我们需要尽可能地少用a来使得s转化为t。
容易计算s和t之间的差值的绝对值diff = abs(s - t),这是我们需要使用若干个a和b凑出来的结果。
假设我们使用了x和a和y个b,那么就存在关系xa + yb = diff。
注意到此时我们并没有区分加减操作,这意味着我们的x和y是可以取负数的(取负数表示减法)。
所以上述问题就转变为,在已知a、b和diff的前提下,我们如何选取y值,才能使得x的绝对值尽可能小。
再换言之,我们可以从0开始,小到大地枚举x,并查看diff-xa和diff+xa是否可以整除b,也就是计算得到合适的整数y。
代码非常简短
# 计算s和t的差值的绝对值diff
diff = abs(s-t)
# 初始化x为0
x = 0
# 进行循环,由于不知道循环次数因为使用while循环
# 从0开始,从小到大枚举x的值
while True:
# 如果diff-x*a或diff+x*a可以整除b,得到合适的y
# 那么此时x即为答案,记录ans后退出循环
if (diff-x*a) % b == 0 or (diff+x*a) % b == 0:
ans = x
break
# 在while循环中x不断增大
x += 1代码
Python
# 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
# 地址:https://www.odalgo.com
# 华为OD机试刷题网站:https://www.algomooc.com
# 添加微信 278166530 获取华为 OD 笔试真题题库和视频
# 输入四个参数
s, t, a, b = map(int, input().split())
# 计算s和t的差值的绝对值diff
diff = abs(s-t)
# 初始化x为0
x = 0
# 进行循环,由于不知道循环次数因为使用while循环
# 从0开始,从小到大枚举x的值
while True:
# 如果diff-x*a或diff+x*a可以整除b,得到合适的y
# 那么此时x即为答案,记录ans后退出循环
if (diff-x*a) % b == 0 or (diff+x*a) % b == 0:
ans = x
break
# 在while循环中x不断增大
x += 1
print(x)Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入四个参数
int s = scanner.nextInt();
int t = scanner.nextInt();
int a = scanner.nextInt();
int b = scanner.nextInt();
// 计算s和t的差值的绝对值diff
int diff = Math.abs(s - t);
// 初始化x为0
int x = 0;
// 进行循环,由于不知道循环次数因此使用while循环
// 从0开始,从小到大枚举x的值
while (true) {
// 如果diff - x * a或diff + x * a可以整除b,得到合适的y
// 那么此时x即为答案,记录ans后退出循环
if ((diff - x * a) % b == 0 || (diff + x * a) % b == 0) {
break;
}
// 在while循环中x不断增大
x++;
}
System.out.println(x);
}
}C++
#include <iostream>
#include <cmath>
int main() {
int s, t, a, b;
// 输入四个参数
std::cin >> s >> t >> a >> b;
// 计算s和t的差值的绝对值diff
int diff = abs(s - t);
// 初始化x为0
int x = 0;
// 进行循环,由于不知道循环次数因此使用while循环
// 从0开始,从小到大枚举x的值
while (true) {
// 如果diff - x * a或diff + x * a可以整除b,得到合适的y
// 那么此时x即为答案,记录ans后退出循环
if ((diff - x * a) % b == 0 || (diff + x * a) % b == 0) {
break;
}
// 在while循环中x不断增大
x++;
}
std::cout << x << std::endl;
return 0;
}C
#include <stdio.h>
#include <stdlib.h>
int main() {
int s, t, a, b;
// 输入四个参数
scanf("%d %d %d %d", &s, &t, &a, &b);
// 计算s和t的差值的绝对值diff
int diff = abs(s - t);
// 初始化x为0
int x = 0;
// 进行循环,由于不知道循环次数因此使用while循环
// 从0开始,从小到大枚举x的值
while (1) {
// 如果diff - x * a或diff + x * a可以整除b,得到合适的y
// 那么此时x即为答案,记录ans后退出循环
if ((diff - x * a) % b == 0 || (diff + x * a) % b == 0) {
break;
}
// 在while循环中x不断增大
x++;
}
printf("%d\n", x);
return 0;
}Node JavaScript
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("", function (input) {
// 输入四个参数
const [s, t, a, b] = input.split(" ").map(Number);
// 计算s和t的差值的绝对值diff
let diff = Math.abs(s - t);
// 初始化x为0
let x = 0;
// 进行循环,由于不知道循环次数因此使用while循环
// 从0开始,从小到大枚举x的值
while (true) {
// 如果diff - x * a或diff + x * a可以整除b,得到合适的y
// 那么此时x即为答案,记录ans后退出循环
if ((diff - x * a) % b === 0 || (diff + x * a) % b === 0) {
break;
}
// 在while循环中x不断增大
x++;
}
console.log(x);
rl.close();
});Go
package main
import (
"fmt"
"math"
)
func main() {
var s, t, a, b int
// 输入四个参数
fmt.Scan(&s, &t, &a, &b)
// 计算s和t的差值的绝对值diff
diff := int(math.Abs(float64(s - t)))
// 初始化x为0
x := 0
// 进行循环,由于不知道循环次数因此使用while循环
// 从0开始,从小到大枚举x的值
for {
// 如果diff - x * a或diff + x * a可以整除b,得到合适的y
// 那么此时x即为答案,记录ans后退出循环
if (diff - x * a) % b == 0 || (diff + x * a) % b == 0 {
break
}
// 在while循环中x不断增大
x++
}
fmt.Println(x)
}时空复杂度
时间复杂度:O(x)。循环次数和两个数之间的大小关系有关,较难预估,需要循环x次。
空间复杂度:O(1)。仅需若干常数空间。
