题解 P9581 宝箱

比赛的时候看电影去了,回来的时候发现有比赛,只能写一篇题解来补偿一下了。

思路

第一眼先看样例。

观察样例,很容易发现,结果总是绝对值小的数的绝对值的两倍加上绝对值大的绝对值的值。

举个栗子:样例三的答案就是 51×2+154=256|51|\times2+|-154|=256

其实也很好理解,因为样例中的三个例子你会发现他会先去距离小的地方,之后再走到另外一个点。

比如说两个点的位置分别为 a,ba,b,其中 a<0,b>0a<0,b>0,如果你先去 aa,则距离为 a+a+b=2a+ba+a+b=2a+b,如果先去 bb,则距离为 b+a+b=a+2bb+a+b=a+2b,两者都有共同的 a+ba+b,只需要比较 a,ba,b 的大小后选择小的即可。

1
2
3
4
5
6
7
8
9
10
#include<bits/stdc++.h>
using namespace std;

int main(){
int a,b; cin >> a >> b;
if(abs(a)>abs(b)) cout << abs(b)*2+abs(a);
else if(abs(a)<abs(b)) cout << abs(a)*2+abs(b);
else if(abs(a)==abs(b)) cout << 3*abs(a);
return 0;
}

代码一交上去,呀,WA on #3 和 #7,但这是为什么呢?

观察三个样例,你会发现它们都是一正一负,当然包括有一个在零点的情况。所以上面我们考虑的情况是他一点要过原点后去到另一个地方。但是如果两个点同时位于同一个半轴,那么这样走就属于绕路,实际上可以直接向远的那个走去,可以顺路,故在这种情况下,答案应该为 max(a,b)\max(|a|,|b|)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<bits/stdc++.h>
using namespace std;

int main(){
int a,b; cin >> a >> b;
if((a>=0 and b<=0)or(a<=b and b>=0)){
if(abs(a)>abs(b)) cout << abs(b)*2+abs(a);
else cout << abs(a)*2+abs(b);
}
else{
cout << max(abs(a),abs(b));
}
return 0;
}

但是这样还是太麻烦了,不符合 T1 一行代码 AC 的性质(逃),所以我们可以继续简化。

我们可以假设我们先从 00aa,那么距离为 a|a|,之后再从 aabb,即 ab|a-b|

如果我们先从 00bb,那么距离为 b|b|,之后再从 bbaa,即 ab|a-b|

所以答案可以简化为 min(a+ab,b+ab)\min(|a|+|a-b|,|b|+|a-b|)

AC代码

C++ 代码:

1
2
3
4
5
6
7
8
#include<bits/stdc++.h>
using namespace std;

int main(){
int a,b; cin >> a >> b;
cout << min(abs(a)+abs(a-b),abs(b)+abs(a-b));
return 0;
}

Python 代码:

1
2
a,b = map(int,input().split(" "))
print(min(abs(a)+abs(b-a),abs(b)+abs(a-b)))

总结一下,这是一道很水的题目,但是我们的做法是越来越简单的。因此,在遇到新的一题时,我们应该多想想,想想更加简便的做法,或者层层递进,或许可以发现另一片新世界。

不要想太多,我只是在想办法掩饰我比较蠢的事实而已。


题解 P9581 宝箱
https://sunnyli.咕咕咕.eu.org/solution-P9581/
作者
SunnyLi
发布于
2023年8月26日
许可协议