题目描述
先附上原题网站:Competition Interface - Kick Start 2018 - Round A - Even Digits(包含分析,科学上网)
问题: Supervin有一个特殊的计算器,该计算器只有一个显示屏,一个加按钮,一个减按钮。现在整数 N
显示在计算器屏幕上。
按加按钮屏幕上数字加1,按减按钮减1,计算器不显示开头的0。比如,现在计算器显示的是100,按减按钮则显示的是99,而不是099。
Supervin不喜欢奇数,因为他觉得"奇"数很"奇"怪。所以他想通过按这个计算器让十进制表示的整数里面包含的数字只有偶数。因为这个计算器有点旧了,按钮也按不太动了,所以他想要按按钮次数最少,
请你帮助Supervin决定让计算器显示的数字没有奇数的最少点击次数。
问题总结: 给定一个数,判断使得该数成为数字全为偶数的最少次数(通过不断加1或不断减1)
输入: 第一行是测试样本的数量 T
,紧接着下面有T
个样例。每行包括一个整数N
限制: 1 ≤ T ≤ 100
;时间限制:每个测试集不超过20s
,存储限制:1GB
小样本数据集:1≤ N ≤ 10^5
大样本数据集:1 ≤ N ≤ 10^16
样例:
Input | Output |
---|---|
4 | |
42 | Case #1: 0 |
11 | Case #2: 3 |
1 | Case #3: 1 |
2018 | Case #4: 2 |
题目分析
小数量级
很显然我们要么一直点加按钮,要么一直点减按钮,因为穿插点会被抵消。所以我们想要么一直减,要么一直加,直到我们得到一个“漂亮”整数。假设M
是得到“漂亮”整数需要减1的最小次数,P
是需要加1的最小次数。则结果就是M
和P
之间的最小值。
注意,对于输入值N
则M
和P
的最大值不超过N
,因为可以一直减1得到0(不超过N
),或者一直加1得到2 * N
(也不超过N)。所以解决小数量级数据时可以全遍历(暴力解法)。
遍历[0 , N]
之间的每一个数 i
看 N + i
或者 N - i
是不是“漂亮”整数。如果得到了“漂亮”整数,i
即为结果。
大数量级
M
表示需要减1的最小次数; P
表示需要加1的最小次数。
为了得到 M
的值,我们需要找到一个比 N
小的最大的“漂亮”整数,假设该数为 X
。同样,为了找到 P
,我们要找到一个比 N
大的最小的“漂亮”整数,假设该数为 Y
。
我们可以这样构造 X
:将 N
中的从左到右第一个奇数减1,然后将这第一个奇数右边的所有的数都替换为最大的偶数8。比如,N = 4436271
,将第一个奇数 3 减一得到 2,再将 2 右边的所有数字都换为8,即 X = 4428888
,这样可能会导致第一个数字变为0(当第一位为1的时候),只要直接去掉就好了。如果本身 N
就没有奇数,则 X = N
这样能保证在 X
和 N
之间不会有“漂亮”整数,因为再大于 X
的“漂亮”整数肯定在第一个奇数上大于N
的第一个奇数。比如在上例中,比 X
更大的“漂亮”整数是 4440000
(4428889,4428890,…443****,…都包含奇数),比N
大。
同样的可以用这个思路构造 Y
:将 N
中从左到右的第一个奇数加1,再将这个数右边的所有数都替换为最小的偶数0。如果本身 N
就没有奇数,则Y = N
。
但有几个问题需要解决。如果第一个奇数是 9 的话,要将这个数左边的数变成比它自己大的偶数(加2)。比如,N = 86912
,那么 Y = 88000
。
另一个需要处理的问题是当第一个奇数左边的数是8的情况。此时需要将8变为0并处理8之前的数字(将8之前的数字再变成比它自己大的第一个偶数),直到没有8为止。比如,如果 N = 6488962
,那么 Y = 6600000
。如果第一个奇数左边全部都是8,或者N
的第一个数就是 9, 那就需要在左边加上一个新的最小非0偶数:2,比如,N = 88892
或者 N = 91112
,那么 Y = 200000
只要得到了 X
和 Y
,就能得到 M
和 P
,然后取M
和P
的最小值即可。
题目解答
import java.util.*;
import java.io.*;
public class Solution{
public static void main(String