ACM离线补题大法-上海金马五校程序设计竞赛 M : Lucky Digits

Time Limit: 1 s

Description

Tommy has a tiny calculator, which only has a display, a plus button, and a minus button. Currently, the integer N is displayed on the calculator.

Pressing the plus button increases the number displayed by 1. Similarly, pressing the minus button decreases the number displayed by 1. And no leading zeros will be displayed on the calculator. For example, if 10 is displayed on the calculator, pressing the minus button once will cause the calculator to display 9.

Tommy only likes digits 2 and 6, because he thinks they are “lucky”. Therefore, he wants to display an integer with only digits 2 and 6, using only the two buttons on the calculator. Since the calculator is old and the buttons are hard to press, he wants to use a minimum number of button presses.

Please help Tommy to determine the minimum number of button presses to make the calculator display an integer with only “lucky” digits.

Input

There are several test cases (no more than 100).

Each test case begins with one line containing an integer N (0 ≤ N ≤ 1018), which is the integer initially displayed on the calculator.

Output

For each test case, output one line containing the minimum number of button presses, as described above.

Sample Explanation

In the first sample case, the integer initially has only “lucky” digits, so no button presses are needed.
In the second sample case, pressing the minus button twice will cause the calculator to display 26.
In the third sample case, pressing the plus button six times will cause the calculator to display 62.
There is no way to satisfy the requirements with fewer button presses in these cases.

Sample Input

626
28
56

Sample Output

0
2
6

问一个数,通过加减变成只有6和2组成的数(比如888变成666),最少需要多少步。

一开始思路有问题,写了一个小时到比赛结束了还是wa,我想着一位一位决策应该改成6还是改成2,比赛后测试出了问题。

然而这时候dhOJ已经关了,怎么补题呢?没关系!可以用师兄的暴力打表ac代码(https://my.csdn.net/lzc504603913)写一个offline judge,然后爆跑1e18的数据来测试!

补题时使用了权哥提点的全新策略,原来不需要按位决策,找到第一位不是“6”也不是“2”的数据之后,如果这一位大于6,那后面自然都是666666(因为要后退,后退找大的);如果这一位小于2,那后面自然都是222222(前进,前进找小的);如果在2和6直接,那就比比622222…..和26666666…..哪个用的步数少。
最后特判一下输入的第一位是1的情况,因为应该是要退位的。

呃,跑了半天都没跑完,后来写了个随机数,测了20000个都没错,就当我过了吧。

ac代码(伪):

public class Main {
    static long MAX_TEST = (long) 1e18;

    public static void main(String[] args) {
        ZeCongOJ zOJ = new ZeCongOJ();
        Random rand = new Random();
        int n = 0;
        while (n++ < MAX_TEST) {
            // System.out.println(wa);
            String in = n + "";
            int len = in.length();
            int start = -1;
            System.out.println("评测进度:" + n + "/" + MAX_TEST);

            for (int i = 0; i < len; i++) {
                char get = in.charAt(i);
                if (get != '6' && get != '2') {
                    start = i;
                    break;
                }
            }

            if (start == -1) {
                if (!zOJ.judge(0, n)) {
                    System.out.println("WA, n = " + in);
                    System.out.println("我找到的数字是:不变");
                    System.out.println("我的答案:0" + " ,聪哥的答案:" + zOJ.getAns(n));
                }
                continue;
            }

            String ans = in.substring(0, start);

            int first = Integer.parseInt(in.substring(start, start + 1));
            if (first > 6) {
                for (int i = start; i < len; i++) {
                    ans += "6";
                }
            } else if (first < 2) {
                for (int i = start; i < len; i++) {
                    ans += "2";
                }
            } else {
                String a = "6";
                String b = "2";
                for (int i = start + 1; i < len; i++) {
                    a += "2";
                    b += "6";
                }
                if (Math.abs(n - Long.parseLong(ans + a)) < Math.abs(n - Long.parseLong(ans + b))) {
                    ans += a;
                } else {
                    ans += b;
                }
            }

            long finalAns = 0;
            if (first == 1 && len > 1) {
                String ans2 = "";
                for (int i = 1; i < len; i++) {
                    ans2 += "6";
                }

                if (Math.abs(n - Long.parseLong(ans)) < Math.abs(n - Long.parseLong(ans2))) {
                    finalAns = Long.parseLong(ans);
                } else {
                    finalAns = Long.parseLong(ans2);
                }
            } else {
                finalAns = Long.parseLong(ans);
            }

            long store = finalAns;
            finalAns = Math.abs(n - finalAns);

            if (!zOJ.judge(finalAns, n)) {
                System.out.println("WA, n = " + in);
                System.out.println("我找到的数字是:" + store);
                System.out.println("我的答案:" + finalAns + " ,聪哥的答案:" + zOJ.getAns(n));
                return;
            }
        }
        System.out.println("AC");
    }
}

class ZeCongOJ {
    ArrayList<Long> li;
    long tot;
    int last;

    public ZeCongOJ() {
        li = new ArrayList<>();
        li.add((long) 2);
        li.add((long) 6);

        for (int k = 1; k < 18; k++) {
            int len = li.size();
            for (int i = last; i < len; i++) {
                tot = 6 * poww(10, k) + li.get(i);
                li.add(tot);
                tot = 2 * poww(10, k) + li.get(i);
                li.add(tot);
            }
            last = len;
        }
    }

    public boolean judge(long ans, long n) {
        return ans == getAns(n);
    }

    public long getAns(long n) {
        long min = Integer.MAX_VALUE;
        for (int i = 0, len = li.size(); i < len; i++) {
            min = Math.min(Math.abs(li.get(i) - n), min);
        }
        return min;
    }

    public long poww(long a, long b) {
        long ans = 1, base = a;
        while (b != 0) {
            if ((b & 1) != 0) {
                ans *= base;
            }
            base *= base;
            b >>= 1;
        }
        return ans;
    }
}

猜你喜欢

转载自blog.csdn.net/cymbals/article/details/80670223