1 solutions

  • 0
    @ 2025-5-3 22:55:53

    [系统测试] A+B Problem ?

    这个题确实和其他 OJ 常规签到的 A+B 不一样,需要考虑的点非常多。很快我们就看到了使用高精度以及 __int128_t 数据类型通过本题的同学们了。接下来给大家简单讲解一下各种做法都是怎么做的。

    1.常规做法

    利用数组模拟高精度运算这个我们就不在这里做赘述了。这里只说使用 g++msvc 编译器都有的 long long 以及 unsigned long long 就能解决的做法。

    输入的整数 aabb 虽然在 long long 范围内,但是 a+ba+b 就不一定了。

    Case 1

    对于一正一负(或者至少一个是 0),必然不会爆 long long 的范围,所以我们照常输出 a+ba+b 即可。

    Case 2

    a,ba,b 均为正数,a+ba+b 就有可能超过 long long 表示范围上限的 26312^{63}-1 导致溢出,此时使用 long long 运算就会输出一个负数。

    在这种情况下我们可以考虑用 unsigned long long。因为两个最大为 26312^{63}-1 的正数相加最大为 26422^{64}-2,不会超出 unsigned long long 的上限 26412^{64}-1,因此直接强制类型转换计算即可。

    Case 3

    a,ba,b 均为负数,将两者取相反数,还用 unsigned long long 计算,计算结果多输出一个负数即可,这样可以应对一般的情况。

    Case 4

    最后一组数据为 a=b=263a=b=-2^{63},两者相加的结果为 264-2^{64},这正好是 unsigned long long 无法存储的情况,因此直接特判并输出对应值 18446744073709551616-18446744073709551616 即可。

    #include <stdio.h>
    int main()
    {
        long long a, b;
        scanf("%lld %lld", &a, &b);
        // a + b 可能超过 long long 最大值 故用必正的 unsigned long long
        if (a >= 0 && b >= 0)
        {
            unsigned long long sum = a + b; 
            printf("%llu\n", sum);
        }
        // 因为一正一非正 故相加不会超过long long范围正常输出即可
        else if (((a > 0 && b <= 0)) || ((a <= 0) && (b > 0)))
        {
            long long sum = a + b; 
            printf("%lld\n", sum);
        }
        // 特判 理由见上
        else if (a == -9223372036854775808ll && b == -9223372036854775808ll)
        {
            printf("-18446744073709551616\n"); 
        }
        // 因为特殊情况已经在上面被讨论 故剩下的可以放开手脚取相反数相加
        else if (a <= 0 && b <= 0)
        { 
            a = -a, b = -b;
            unsigned long long sum = a + b;
            printf("-%llu\n", sum);
        }
        return 0;
    }
    

    2.__int128_t 做法

    在 64 位架构的 g++ 编译器中,除了 8,16,32,64 位整数之外,还有 128 位整数 __int128_t__uint128_t 的存在(但是 msvc 就无法使用了,因此也不建议大家用 Visual Studio 来刷题),数据表示范围对应进行了扩增。

    但是 128 位整数没有自带的输入/输出/哈希值等内容(也就意味着用 STL 存储 128 位整数时需要注意)。因此我们利用字符串处理的基础思想,使用 getcharputchar 输入输出即可。使用 getchar/putchar 的输入输出速度优于 scanf/printf,此外还有 fread/fwrite 等更加快速的函数。我们会在其他的系统测试题目中为大家介绍。

    注意到 2127-2^{127} 无法使用 putchar 进制转换的方式输出,因此也需要特判一下才能实现完整功能。但是对于本题自然是不需要的。

    #include <stdio.h>
    #include <ctype.h>
    typedef __int128_t i128;
    const i128 DINF128 = ((i128)(((long long)1) << 63)) << 64;
    i128 rd()
    {
        i128 k = 0, f = 1;
        char s = getchar();
        while (!isdigit(s)) f = (s == '-') ? 0 : f, s = getchar();
        while (isdigit(s)) k = (k << 1) + (k << 3) + (s ^ '0'), s = getchar();
        return f ? k : -k;
    }
    void wr(i128 x)
    {
        if (x == DINF128) return (void)(puts("-170141183460469231731687303715884105728"));
        if (x < 0) x = -x, putchar('-');
        if (x > 9) wr(x / 10);
        putchar((x % 10) ^ '0');
    }
    int main() { wr(rd() + rd()); }
    

    3.Python 做法

    Python 的话和一般的 a+b 无异,原样输出即可。这是因为 Python 的 int 可以表示的范围非常大。但是除此之外,Python 在程序设计习题当中几乎没有其他优势。

    a, b = map(int, input().split())
    print(a + b)
    
    • 1

    Information

    ID
    1
    Time
    1000ms
    Memory
    512MiB
    Difficulty
    1
    Tags
    # Submissions
    59
    Accepted
    11
    Uploaded By