程序计算不包含给定数字的第n个数字

时间:2019-02-24 11:18:06

标签: c++ algorithm

我被要求编写一个C ++程序,该程序计算包含给定数字且执行时间小于0.1秒内存似乎不是问题,因为我最多可以使用64 MB。

问题的原始文本如下:

Cifra4

  

对于represent numbers,决定不使用数字C   再次。   因此,从自然数数组中,所有包含   C位将被删除。让新数组为 S

     

要求

     

1)确定 S 中的N-th号。

     

2) YZ是两个自然的   所有自然数数组中的数字。确定数量
  从YZ的自然数。

     

输入数据

     

输入文件cifra4.in包含第一个数字T,代表   需求类型。如果为T == 1,第二行将包含   数字C和数字N。如果T == 2,则   第二行将包含数字C和两个自然数Y,并且   Z

     

输出数据

     

在输出文件cifra4.out中将包含第一行   根据要求的类型一个自然数。

     

限制和说明

1 ≤ N ≤ 10 ^ 13
0 ≤ C ≤ 9
1 ≤ Y ≤ 10 ^ 13
1 ≤ Z ≤ 10 ^ 13
for 20% of the tests, N will have a maximum of 5 digits
for 20% of the tests, Y and Z will have a maximum of 6 digits
     

示例1

     

cifra4.in

1
0 11
     

cifra4.out

12
     

示例2

     

cifra4.in

2
1 3 20
     

cifra4.out

     

10

我最好的尝试是确定(或至少应该确定)不包含数字“ 0”的第n个数字的代码,但是对于10 ^ 13,它返回了23210987654321,其中显然包含0

我最终选择了慢一点但正确的方法。这是代码:

#include <fstream>

std::ifstream in("cifra4.in");
std::ofstream out("cifra4.out");

const long long pow_of_10[14] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
                                 10000000000, 100000000000, 1000000000000};

void req_1 ()
{
    short digit;
    long long n;
    in >> digit >> n;
    for (long long i = 0; i <= n; i++)
    {
        long long nr = i;
        if (nr)
        {
            long k = 1;
            do
            {
                if (nr % 10 == digit)
                {
                    n += pow_of_10[k];
                    i += pow_of_10[k] - 1;
                    break;
                }
                nr /= 10;
                k++;
            }
            while (nr);
        }
        else if (digit == 0) n++;
    }
    out << n - 1;
}

void req_2()
{
    short digit;
    long long lhs, rhs;
    long long elim = 0;
    in >> digit >> lhs >> rhs;
    for (long long i = lhs; i <= rhs; i++)
    {
        long long nr = i;
        while (nr)
        {
            if (nr % 10 == digit)
            {
                elim++;
                break;
            }
            nr /= 10;
        }
    }
    out << elim;
}

int main()
{
    short requirement;
    in >> requirement;
    if (requirement == 1)
        req_1();
    else
        req_2();
}

注意

我并不是在需要代码,而是想出一些主意,可能的算法可以在适当的时间(最好是问题所要求的时间)执行多达10 ^ 13的算法,但是1秒钟对我来说很好。

2 个答案:

答案 0 :(得分:3)

假设9是禁止的数字。在这种情况下,您只需将数字转换为9即可。

现在,如果禁止数字不同,例如d,会发生什么?它仍然是一个以9为底的数字,但是您必须映射数字,以使d以下的数字保持不受影响,而d及以上的数字被映射到数字d + 1

例如,当禁止数字为7n125时。

  • 第1步:转换为以9为基数:125 10 = 148 9
  • 第2步:映射数字。 1→1,4→4,8→9

解决方案是149。

答案 1 :(得分:0)

由于数字的十进制数字彼此“独立”,因此设置一个数字不会影响任何其他数字-一旦您固定了(至少一个)更高有效数字的前缀,则保留n '无关紧要的数字,您知道您有(10-1)^ n'= 9 ^ n'个具有该前缀的数字,并且未固定部分中没有禁止的数字。例如,对于以1开头的3位数字,确切地说有81个数字,其中没有0。

此处唯一的“误读”是将最高有效位设置为零表示您为不同位数(012、0012等)获得相同的数字。但是,您也应该能够解决此问题-通过确定第n个数字(不含禁止的数字)所需的位数。与我上面描述的论点非常相似。那么您知道如果禁止数字为0,则那里有10-1 = 9个选项,否则为10-2 = 8。