zoukankan      html  css  js  c++  java
  • Google Code Jam 2016 Round 1B B

    题意:给出两个数字位数相同,分别中间有若干位不知道,用问号表示。现在要求补全这两个数字,使得差值的绝对值最小,多解则取第一个数字的值最小的,再多解就取第二个数字最小的。

    分析:

    类似数位dp,但是很多状态可以直接得出最终解,个别状态需要状态转移。

    我们从高位到低位依次确定两个数的每个位是几。一旦确定了两个数的一个位不一样,则可以立即将小的一方的后续问号全部写9,大的一方后续问号全部写0。这样才能让差值最小。

    那我们观察每个位的时候要如何确定其值呢?分如下几种情况。

    1.两个数的该位都是问号,那么分三种情况:

      1.1 都标为0,看下一个位。

      1.2&1.3 将一位标为1,另一个位标为0,并更新答案,终结状态。(这表示我们主动在高位制造了一个差值以便后面取得整体差值最小。例如:?0?,?9?,答案是100,099)

    2.两个数的该位都不是问号,若相等,继续看下一位。若不等,则标出后面问号,更新答案,终结状态。

    3.两个数的该位有一个是问号,那么这个这与第一种情况类似,分三种情况处理。

      3.1 标为与该位相等,看下一个位。

      3.2 标为该位减1,赋值后续问号,更新答案,终结状态。

      3.3 标为该位加1,赋值后续问号,更新答案,终结状态。

    就这么多情况。值得注意的是,虽然有些时候进行了状态转移(看下一个位)。但是并不需要搜索和回溯。因为每个状态的多个分支中,只有一个是状态转移,其他的都是最终态。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    #define d(x) 
    
    const int MAX_LEN = 20;
    
    char st[2][MAX_LEN];
    char ans[2][MAX_LEN];
    char temp[2][MAX_LEN];
    long long diff;
    int n;
    
    void input()
    {
        scanf("%s", st[0]);
        scanf("%s", st[1]);
        n = strlen(st[0]);
    }
    
    long long get_value(char st[])
    {
        long long ten = 1;
        long long ret = 0;
        for (int i = n - 1; i >= 0; i--)
        {
            ret += (st[i] - '0') * ten;
            ten *= 10;
        }
        return ret;
    }
    
    bool ok(long long temp_diff)
    {
        if (temp_diff > diff)
            return false;
        if (temp_diff < diff)
            return true;
        if (strcmp(ans[0], temp[0]) > 0)
            return true;
        if (strcmp(ans[0], temp[0]) < 0)
            return false;
        return strcmp(ans[1], temp[1]) > 0;
    
    }
    
    void update()
    {
        long long a = get_value(temp[0]);
        long long b = get_value(temp[1]);
        long long temp_diff = abs(a - b);
        if (ok(temp_diff))
        {
            diff = temp_diff;
            strcpy(ans[0], temp[0]);
            strcpy(ans[1], temp[1]);
        }
    }
    
    void make(int index, int a, int b)
    {
        if (a < 0 || b < 0 || a > 9 || b > 9)
            return;
    
        strcpy(temp[0], st[0]); 
        strcpy(temp[1], st[1]); 
    
        temp[0][index] = a + '0';
        temp[1][index] = b + '0';
    
        int ch_a = '9';
        int ch_b = '0';
        if (a > b)
            swap(ch_a, ch_b);
        for (int i = index + 1; i < n; i++)
        {
            if (temp[0][i] == '?')
                temp[0][i] = ch_a;
            if (temp[1][i] == '?')
                temp[1][i] = ch_b;
        }
        d(printf("a=%d
    ", a));
        d(printf("b=%d
    ", b));
        d(puts(temp[0]));
        d(puts(temp[1]));
        update();
    }
    
    void work()
    {
        diff = 1LL << 62;
        for (int i = 0; st[0][i]; i++)
        {
            if (st[0][i] == st[1][i] && st[0][i] != '?')
            {
                continue;
            }
            if (st[0][i] == st[1][i] && st[0][i] == '?')
            {
                make(i, 0, 1);
                make(i, 1, 0);
                st[0][i] = st[1][i] = '0';
                continue;
            }
            //reach here means st[0][i] != st[1][i]
            if (st[0][i] != '?' && st[1][i] != '?')
            {
                make(i, st[0][i] - '0', st[1][i] - '0');
                return;
            }
            //reach here means only one of them is ?.
            if (st[0][i] == '?')
            {
                make(i, st[1][i] - '0' + 1, st[1][i] - '0');
                make(i, st[1][i] - '0' - 1, st[1][i] - '0');
                st[0][i] = st[1][i];
            }
            if (st[1][i] == '?')
            {
                make(i, st[0][i] - '0', st[0][i] - '0' + 1);
                make(i, st[0][i] - '0', st[0][i] - '0' - 1);
                st[1][i] = st[0][i];
            }
    
        }
        make(n - 1, st[0][n - 1] - '0', st[1][n - 1] - '0');
    }
    
    int main()
    {
        int t;
        scanf("%d", &t);
        int case_num = 0;
        while (t--)
        {
            case_num++;
            printf("Case #%d: ", case_num);
            input();
            work();
            printf("%s %s
    ", ans[0], ans[1]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    转载:稳定性,鲁棒性和非脆弱性的精辟解读
    BZOJ 2806: [Ctsc2012]Cheat(单调队列优化dp+后缀自动机)
    CF 235C. Cyclical Quest(后缀自动机)
    BZOJ 5137: [Usaco2017 Dec]Standing Out from the Herd(后缀自动机)
    2019/2/28 考试记录
    后缀自动机的应用
    CF 452E. Three strings(后缀数组+并查集)
    BZOJ 2281: [Sdoi2011]黑白棋(dp+博弈论)
    CF 39E. What Has Dirichlet Got to Do with That?(记忆化搜索+博弈论)
    LUOGU P4783 【模板】矩阵求逆(高斯消元)
  • 原文地址:https://www.cnblogs.com/rainydays/p/5533435.html
Copyright © 2011-2022 走看看