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)
。仅需若干常数空间。