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\n", a));
    d(printf("b=%d\n", 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\n", ans[0], ans[1]);
    }
    return 0;
}

时间: 2024-10-04 00:33:34

Google Code Jam 2016 Round 1B B的相关文章

Google Code Jam 2014 Round 1B Problem B

二进制数位DP,涉及到数字的按位与操作. 查看官方解题报告 #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; #define MAX_LEN 50 long long A, B, K; int a[MAX_LEN], b[MAX_LEN], k[MAX_LEN]; long long memoize[MAX_LEN]

Google Code Jam 2016 Round 1C C

题意:三种物品分别有a b c个(a<=b<=c),现在每种物品各选一个进行组合.要求每种最和最多出现一次.且要求任意两个物品的组合在所有三个物品组合中的出现总次数不能超过n. 要求给出一个方案,使得我们能够生成的组合数最多. 分析: 首先我们可以简单的处理一种情况,就是c<=n的情况. 因为我们枚举出了所有组合,那么两物品的出现次数的最大值不会超过c,因为A种和B种的每对组合都会在其中出现c次,其余两个的组合出现次数更少. 所以这种情况一定不会超过n,我们只需要枚举所有组合即可. 然而

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

Problem In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall with a window separates adjacent cells, and

Google Code Jam 2014 Round 2回顾和分析

回顾 比赛开始网络就一直在抽风,不知道宿舍网渣还是有人攻击服务器.刷了n遍n久刷出了题目.提交A小case的时候眼睁睁看着时间过去,却提交不上,这破网.最后A题B题还是解决了,C题扫了一眼,读都没读,就奔D题去了,因为我看到了熟悉的trie这个单词,加之看到小case只有9分,判断小case应该比较容易.前面因为网络浪费了很多时间,加之从未编过trie的程序,只能临时上网翻书去学,最后D小这个可以很容易暴力解的问题也没编完. 最终的rank是13xx,考虑到在这次GCJ之前从未接触过编程竞赛,而

2015 Google code jam Qualification Round B 枚举 + 贪心

题意:给你一个无穷长的数列 和一些非 0 的值,可以进行两种操作. 1)数列中所有大于1的值 都减1 2)从 a[i] 中取出任意的值分给任意人. 问你最少执行多少步能使的 数列全为0. 解题思路:枚举最大的a[i].大于 a[i]的部分都分出去. 解题代码: 1 // File Name: b.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月11日 星期六 23时16分58秒 4 5 #include<vector> 6 #incl

Google Code Jam 2015 Round 1A Mushroom Monster 水

题意:每10秒扫描一下盘子,查看盘子里面的面包个数,问你主角用两种吃法可能吃得的最少的面包. 1)任意吃. 2)每秒以恒定速度. 解题思路:暴力,找差值. 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时52分04秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #includ

Google Code Jam 2015 Round 1A Haircut 二分

题意:给你每个理发师的理发时间,问你排在队列中的第N个位置,问你应该被哪个理发师剪发. 解题思路:二分时间,看这个时间到第几个人理发了,然后找到临界值,看这个值的时候有那些理发师接待了新旅客的,即可找到那个理发师. 解题代码: 1 // File Name: b.sample.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时05分30秒 4 5 #include<vector> 6 #include<lis

2015 Google code jam Qualification Round A 水

题意:给你一个序列 从 0-n  初始位置为0 ,只能从 i 走到 i+1  你必要有的人数 >= i+1  ,每个位置有a[i]个人,问你走到 n 还需要多少个人. 解题思路:暴力 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月11日 星期六 23时06分57秒 4 5 #include<vector> 6 #include<list> 7 #include<

Google Code Jam 2019 Round 1A 题解

A. Alien Rhyme 题意: 思路:将字符反向插入一颗Trie,然后自下而上的贪心即可,即先选后缀长的,再选后缀短的. 实现: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <iomanip> 5 6 #include <vector> 7 #include <cstring> 8 #include <string>