Arithmetic error from 20 decimal places in C

Asked

Viewed 511 times

1

I’m solving Uri Online Problem 1120. The problem is given a number D such that 1 D 9, and a number N such that 1 N < 10¹ I remove all occurrence of D in N. Examples and test cases:

Entrances:

5 5000000  
3 123456  
9 23454324543423  
9 99999999991999999  
7 777  
0 0  

Outputs:(a line in brace after the final output)

0  
12456  
23454324543423  
1  
0  

I already did some research to try to solve the problem,I changed my code so that I could see the results of the variables at each execution and nothing. I’m always getting the message from "Wrong Answer (90%)".

The cases of tests given present identical answers to mine, but testing here I observed that from 20 decimal places the program produces unexpected results.

My code:

/*Esta dando certo pra números de ate 19 dígitos*/

#include<bits/stdc++.h>

#include <math.h>


using namespace std;

int main(){

    int d = 0;
    long long int n = 0, resp = 0;

    while(scanf("%d %lld", &d, &n) && d && n){

        long long int aux = 0;

        for(long long int i = 0; n != 0;){

            //Separo o ultimo número
            aux = n % 10;
            n = n / 10;

            //avalio o número
            if(aux != d){

                resp += ( aux * (int)pow(10, i) );
                i++;
            }

        }//end for

        //Printa a resposta
        printf("%lld\n", resp);
        resp = 0;
    }//end wile

    return 0;
}//end main

NOTE: The program is tested with more test cases than the given, and says that the number N can be a large number.

1 answer

5


This is a competitive programming problem. Whoever does this kind of problem knows which algorithm you need to use to solve it. And try to row against the current, solve the problem in a different way than the original design will result in waste of time or miserable failure.

A waste of time happens when you try to kill flies with bazookas. For example, in a competition within the college, the proof director elaborated a question to search for one string within the other. The problem was similar to this, but I could use the library string.h. My team spent a lot of time on it, implementing the search for substring KMP, when those who prepared the proof simply wanted a strstr like the @Isac noted in his reply.

The pitiful flaw is when you try to kill dragons with fly swatters. See that question and my answer to realize that any solution other than Pisano sequence will not return in a timely manner.


Before I address your question, I’m going to talk about a competitive scheduling issue that my crew and I created to stimulate college freshmen.

Phoenician-Portuguese

Rudy, associate of Uece, Union of Students of Epic Cultures, was researching in a Portuguese tomb and found a tablet with characters similar to found in the fourteenth century Portuguese alphabet. As a good researcher, he realized that there were no vowels in these scriptures, as soon as he realized that it was a culture residual expertise in that area. After much study, he realized that this was one of the first forms of writing that appeared in Portugal, with reports of similar writing in Lisbon.

As the tablet, even putting vowels in words, remained illegible, Rudy theorized that the "Phoenician-Portuguese" read their writings from right to left.

You, as Rudy’s good friend and programmer, volunteered to help his friend in his research, transforming words from our writing into Phoenician-Portuguese writing.

Example of input/output

thiago       | ght
maratona     | ntrm
kiwi         | wk

Notice any resemblance to your problem? Yes, it’s almost the same thing. You read information and return it after doing some deletions. There are three differences between the issues:

  1. in "Phoenician-English", the output is reversed
  2. in your problem, you need to worry about the case of erasing all information
  3. in "Phoenician-English", there are 5 characters to be removed, instead of only 1

Tips from the person who wrote the question

The author of the question is very aware of what he wants. So he already makes it clear to the competitors what kind of information he has. In this case, we have to 1 <= N <= 10^100. This absurd size is the tip he left.

To represent this number, how many bits would it take? Well, just apply the log2 number, right? That would be 100 * log2(10), but we are talking about competitive programming and we cannot spend time calculating the log2.

We know that 10^3 ~~ 2^10, then 10^100 ~~ (10^3)^33. Thereby, 10^100 ~~ (10^3)^33 ~~ (2^10)^33 = 2^330. That is, around 330 bits. Well, you will have a hard time trying to assemble your own whole type with that size...

Or we can treat it as a word processing problem. Simple as that. Where’s the math? Doesn’t matter much, arithmetic isn’t around.

All you need to do is turn one string into another. All you need to do is read the entire line, separate the first character that is the character to be ignored, skip the space, and then process the rest of the line, down to the \n.

To read a line, you can use the fgets. The number of characters to be read is limited by two factors:

  1. the numerical argument you pass
  2. find an EOL

Read more about fgets; here too

In this case, the format of the input is:

  • a digit character
  • a space
  • between 1 and 100 digit characters
  • the line break \n

Then the fgets limited to 1+1+100+1 and the null terminator \0 is enough to read any line of the given problem. Therefore, fgets(entrada, 104, stdin) makes the entrance perfectly.

After that, we will process the characters from entrada[2] until you find the line break.

The processing to be done is: if the character is distinct from entrada[0], prints this character. And only this. As the intention is to read until you find an index i such that entrada[i] == '\n', so we can iterate this way here:

char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
fgets(entrada, 104, stdin);
int i = 2;

while (entrada[i] != '\n') {
  if (entrada[i] != entrada[0]) {
    imprime(entrada[i]);
  }
  i++;
}

We still have to define what this character print routine would look like. So, come on? Print this character?

Since we’re dealing with competitive programming, we don’t need to miss performance with poorly made I/O. Then the best is to bufferize my output and print a single string. How? So:

char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
fgets(entrada, 104, stdin);
int i = 2;
int j = 0;
char saida[200];

while (entrada[i] != '\n') {
  if (entrada[i] != entrada[0]) {
    saida[j] = entrada[i];
    j++;
  }
  i++;
}
saida[j] = '\0'; // pondo o terminador nulo para o C tratar como string 
printf("%s\n", saida);

It seems all quiet, but has not yet dealt with the special case: when it is asked to ignore a digit and the following string is composed exclusively of that digit. In this case, you should print a line with only the character '0' on it:

char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
fgets(entrada, 104, stdin);
int i = 2;
int j = 0;
char saida[200];

while (entrada[i] != '\n') {
  if (entrada[i] != entrada[0]) {
    saida[j] = entrada[i];
    j++;
  }
  i++;
}

// o j só é igual a zero no caso de exceção 
if (j != 0) {
  saida[j] = '\0'; // pondo o terminador nulo para o C tratar como string 
  printf("%s\n", saida);
} else {
  printf("0\n");
}

Well, now we’re missing the zeros print cases left, which should be avoided... If by any chance entrada[i] == '0' and j == 0, then I must not allow this value to be entered:

char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
fgets(entrada, 104, stdin);
int i = 2;
int j = 0;
char saida[200];

while (entrada[i] != '\n') {
  if (entrada[i] != entrada[0]) {
    if (j == 0 && entrada[i] == '0') {
      // ignora
    } else {
      saida[j] = entrada[i];
      j++;
    }
  }
  i++;
}

// o j só é igual a zero no caso de exceção 
if (j != 0) {
  saida[j] = '\0'; // pondo o terminador nulo para o C tratar como string 
  printf("%s\n", saida);
} else {
  printf("0\n");
}

I can simplify this logic at one point yet: it does not need two conditionals one within the other. The previous example was merely illustrative. I can also use !j, since in C the value 0 is already untrue:

char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
fgets(entrada, 104, stdin);
int i = 2;
int j = 0;
char saida[200];

while (entrada[i] != '\n') {
  if (entrada[i] != entrada[0] && !(!j && entrada[i] == '0')) 
    saida[j] = entrada[i];
    j++;
  }
  i++;
}

// o j só é igual a zero no caso de exceção 
if (j != 0) {
  saida[j] = '\0'; // pondo o terminador nulo para o C tratar como string 
  printf("%s\n", saida);
} else {
  printf("0\n");
}

Okay, finished algorithm. But to fully solve the issue, we need to identify when the question stopped. And the stop condition is: the given digit D that will be ignored is '0'. So it looks something like this:

#include <stdio.h>

int main() {
  // for (;;) é uma das maneiras de fazer laço infinito
  for (;;) {
    char entrada[200]; // sim, posso alocar somente 104, mas 200 é mais bonito 
    fgets(entrada, 104, stdin);
    // detectando se o dígito D é 0, condição para parar execução do programa
    if (entrada[0] == '0') {
      return 0;
    }
    int i = 2;
    int j = 0;
    char saida[200];

    while (entrada[i] != '\n') {
      if (entrada[i] != entrada[0] && !(!j && entrada[i] == '0')) 
        saida[j] = entrada[i];
        j++;
      }
      i++;
    }

    // o j só é igual a zero no caso de exceção 
    if (j != 0) {
      saida[j] = '\0'; // pondo o terminador nulo para o C tratar como string 
      printf("%s\n", saida);
    } else {
      printf("0\n");
    }
  }
}

If by chance it is required that the C used is ANSI-C 89, then the declaration of variables needs to be in block start.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.