Errores comunes a evitar en Programación Competitiva en C++ | Principiantes

  1. No usar 1LL o 1ll cuando sea necesario

    // A program shows problem if we
    // don't use 1ll or 1LL
    #include <iostream>
    using namespace std;
    int main()
    {
        int x = 1000000;
        int y = 1000000;
      
        // This causes overflow even
        // if z is long long int
        long long int z = x*y;
      
        cout << z;
        return 0;
    }
    Output: -727379968
    

    Es posible que obtenga algún otro valor negativo como salida. Entonces, ¿cuál es el problema aquí? Los enteros no se promocionan mucho antes de la multiplicación, siguen siendo enteros y su producto también. Luego, el producto se lanza demasiado, pero ahora estamos retrasados ​​porque ya se ha producido un desbordamiento. Tener uno de x o y tan largo debería funcionar, ya que el otro sería promovido. También podemos usar 1LL (o 1ll). LL es el sufijo de long long, que es de 64 bits en la mayoría de las implementaciones de C/C++. Entonces 1LL, es un 1 de tipo long long.

    // C++ program to show that use of 1ll
    // fixes the problem in above code.
    #include <iostream>
    using namespace std;
    int main()
    {
        int x = 1000000;
        int y = 1000000;
      
        long long int z = 1LL*x*y;
      
        cout << z;
        return 0;
    }
    Output: 1000000000000
    

    Aquí hay otro lugar donde este truco puede ayudarte.

    // Another problematic code that doesn't 
    // use 1LL or 1ll
    #include <iostream>
    using namespace std;
      
    int main()
    {
        // we should use 1LL or 1ll here
        // instead of 1. The correct statement
        // is "long long int z = 1LL << 40;"
        long long int z = 1 << 40;
        cout << z;
        return 0;
    }
    Output: 0
    
  2. No usar cin.ignore() con getline

    // A program that shows problem if we
    // don't use cin.ignore()
    #include <iostream>
    using namespace std;
      
    int main()
    {
        int n;
        cin >> n;
        string s;
        for(int i = 0; i<n; ++i)
        {
            getline(cin, s);
            cout << s.length() << " ";
            cout << s << endl;
        }
        return 0;
    }
    Input:
    4
    a b
    c d
    e f
    g h
    Output:
    0 
    3 a b
    3 c d
    3 e f
    

    Entonces, ¿cuál es el problema aquí?
    Esto tiene poco que ver con la entrada que proporcionó usted mismo, sino más bien con el comportamiento predeterminado que exhibe getline(). Cuando proporcionó su entrada para el número entero n (cin >> n), no solo envió lo siguiente, sino que también se agregó una nueva línea implícita a la transmisión:

        "4\n"

    Siempre se agrega una nueva línea a su entrada cuando selecciona Entrar o Regresar al enviar desde una terminal. También se usa en archivos para pasar a la siguiente línea. La nueva línea se deja en el búfer después de la extracción en n hasta la siguiente operación de E/S donde se descarta o se consume. Cuando el flujo de control llega a getline(), la nueva línea se descartará, pero la entrada cesará inmediatamente. La razón por la que esto sucede es porque la funcionalidad predeterminada de esta función dicta que debería hacerlo (intenta leer una línea y se detiene cuando encuentra una nueva línea).

    Debido a que esta nueva línea inicial inhibe la funcionalidad esperada de su programa, se deduce que debe omitirse o ignorarse de alguna manera. Una opción es llamar a cin.ignore() después de la primera extracción. Descartará el siguiente carácter disponible para que la nueva línea ya no sea intrusiva.
    cin.ignore(n, delim) ;
    Esto extrae caracteres de la secuencia de entrada y los descarta, hasta que se extraen n caracteres o uno se compara igual a delim.

    // C++ program to show that use of cin.ignore()
    // fixes the problem in above code.
    #include <iostream>
    using namespace std;
      
    int main()
    {
        int n;
        cin >> n;
        string s;
        cin.ignore(1, '\n');
        for (int i = 0; i<n; ++i)
        {
            getline(cin, s);
            cout << s.length() << " ";
            cout << s << endl;
        }
        return 0;
    }
    Input:
    4
    a b
    c d
    e f
    g h
    Output:
    3 a b
    3 c d
    3 e f
    3 g h
    

    Pero, ¿qué sucede si no sabemos cuántas líneas de entrada habrá? Podemos usar esto entonces:

    // C++ program to handle cases when we
    // don't know how many lines of input 
    // are going to be there
    #include <iostream>
    using namespace std;
    int main()
    {
        string s;
        while (getline(cin, s))
        {
            if (s.empty())
                break;
            cout << s << endl;
        }
        return 0;
    }
    Input:
    a b
    c d
    e f
    g h
    
    Output:
    a b
    c d
    e f
    g h
    
  3. Un problema cuando se toman restos: en muchos problemas, debe imprimir su solución en un módulo primo grande (por ejemplo, 10 ^ 9 + 7).

    // Below program shows problem if we
    // don't use don't take remainders
    // properly.
    #include <iostream>
    #define mod 1000000007
    using namespace std;
      
    int main()
    {
        long long int x, y, z;
        cin >> x >> y >> z;
        z = (z + x*y)%mod; // not good practice
        cout << z;
        return 0;
    }

    Dado que z + x*y podría no encajar en long long, el código anterior puede causar problemas. La mejor manera es hacer esto:

    // Program to demonstrate proper
    // ways of taking remainders.
    #include <iostream>
    #define mod 1000000007
    using namespace std;
      
    int main()
    {
        long long int x, y, z;
        cin >> x >> y >> z;
      
        // good practice
        z = ((z%mod) + ((x%mod)*(y%mod))%mod) % mod;
        cout << z;
        return 0;
    }

    Esto puede ahorrarle muchas respuestas incorrectas, por lo que es mejor tomar mod después de cada cálculo que pueda exceder mucho tiempo. Los casos de prueba generalmente están diseñados para asegurarse de que ha manejado los casos de desbordamiento correctamente.
    ¿Por qué funciona esto?
    Porque (z + x*y)%mod es lo mismo que ((z%mod) + ((x%mod)*(y%mod))%mod)%mod.

  4. cin y cout pueden causar TLE: en muchos programas, la causa de TLE generalmente se basa en su algoritmo. Por ejemplo, si n = 10 ^ 6 y su algoritmo se ejecuta en O (n ^ 2), entonces esto no pasará un límite de tiempo de 1 segundo. Pero digamos que ha encontrado un algoritmo que se ejecuta en O(n) para n = 10^6. Esto debería pasar el límite de tiempo de 1 segundo.
    ¿Qué pasa si esto está fallando?
    Una posible razón es que está utilizando cin y cout para E/S en varios casos de prueba.
    Puede usar scanf o printf para lo mismo. También puede usar alguna función de E/S rápida personalizada para lo mismo basada en algo como getchar() y putchar().

    scanf e printf son más rápidos que cin y cout. Vea esto para más detalles.

    Funciones de E/S rápidas personalizadas:

    // C++ program to demonstrate fast input and output
      
    // use long long x = fast_input(); to read in x
    inline long long int fast_input(void)
    {
        char t;
        long long int x=0;
        long long int neg=0;
        t = getchar();
        while ((t<48 || t>57) && t!='-')
            t = getchar();
        if (t == '-') //handle negative input
        {
            neg = 1;
            t = getchar();
        }
        while (t>=48 && t<=57)
        {
            x = (x<<3) + (x<<1) + t - 48;
      
            // x<<3 means 8*x and x<<1 means 2*x so we
            // have x = 10*x+(t - 48)
            t = getchar();
        }
      
        if (neg)
            x = -x;
        return x;
    }
      
      
    // use fast_output(x, 0); to print x and a newline
    // use fast_output(x, 1); to print x and a ' ' after
    // the x
    inline void fast_output(long long int x, int mode)
    {
        char a[20];
        long long int i=0, j;
        a[0] = '0';
        if (x < 0)
        {
            putchar('-');
            x = -x;
        }
        if (x==0)
           putchar('0');
        while (x)
        {
            // convert each digit to character and
            // store in char array
            a[i++] = x%10 + 48;
            x /= 10;
        }
      
        // print each character from the array
        for (j=i-1; j>=0; j--)
            putchar(a[j]);
      
        if (mode == 0)
           putchar('\n');
        else putchar(' ');
    }

Artículos relacionados:
Una mejor manera de abordar la programación competitiva
Trucos de C++ para la programación competitiva (para C++ 11)
Escribir código C/C++ de manera eficiente en la programación competitiva

Este artículo es una contribución de Hemang Sarkar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *