9 条题解

  • 7
    @ 2024-1-29 20:16:49

    前言

    在本地运行需要加上以下代码:

    import sys
    sys.set_int_max_str_digits(0)
    

    提交时需要去掉,不然会RE


    这篇题解中自定义的函数如下: plus(a:str,b:str)->str返回 a+ba+b

    minus(a:str,b:str)->str返回 aba-b

    multiply(a:str,b:str)->str返回 a×ba \times b

    opposite(a:str)->str返回 a-a

    judge(a:str,b:str)如果 a>ba>b,返回False;如果 a<ba<b,返回True;如果a=ba=b,返回None。

    division(a:str,b:str,accuracy:int)->str返回 ab\frac{a}{b},保留 accuracy 位小数。

    rounding_down(a:str,accuracy:int)->str返回 aa 保留 accuracy 位小数后的结果。

    decimal_to_fraction(a:str)返回转分数后的 aa 的分母,aa 的整数部分,aa 的小数部分的分子。

    abs1(a:str)->str返回 a|a|

    power1(a:str,b:str,accuracy:int)->str返回 aba^b 保留 accuracy 位小数后的结果。

    root(a:str,b:str,accuracy:int)->str返回 ab\sqrt[b]{a} 保留 accuracy+int(b)*10 位小数后的结果。

    高精加/减/乘

    众所周知,python是自带高精度的,也就是说,在进行整数的加/乘运算时不会有误差。所以我们可以先去掉小数点,然后直接用自带的+和*计算,最后在加上小数点;减去一个数等于加上这个数的相反数。这里避免抄袭,只放加法的代码:

    def plus(a:str,b:str) -> str:
        decimal_place_a = a.find('.')
        decimal_place_b = b.find('.')
        if decimal_place_a == -1:
            if decimal_place_b == -1:
                return str(int(a)+int(b))
            else:
                decimal_place_a = 0
        elif decimal_place_b == -1:
            decimal_place_b = 0
        if decimal_place_a != 0:
            decimal_place_a = len(a)-decimal_place_a-1
        if decimal_place_b != 0:
            decimal_place_b = len(b)-decimal_place_b-1
        if decimal_place_a > decimal_place_b:
            b += '0'*(decimal_place_a-decimal_place_b)
        elif decimal_place_a < decimal_place_b:
            a += '0'*(decimal_place_b-decimal_place_a)
        a = a.replace('.','',1)
        b = b.replace('.','',1)
        a = int(a)
        b = int(b)
        c = list(str(a+b))
        decimal_place_c = max(decimal_place_a,decimal_place_b)
        minus_c = False
        if c[0] == '-':
            c.pop(0)
            minus_c = True
        if len(c) > decimal_place_c:
            c.insert(len(c)-decimal_place_c,'.')
        else:
            for i in range(decimal_place_c-len(c)):
                c.insert(0,'0')
            c.insert(0,'.')
            c.insert(0,'0')
        for i in range(len(c)-1,0,-1):
            if c[i] == '0':
                c.pop(i)
            elif c[i] == '.':
                c.pop(i)
                break
            else:
                break
        if minus_c and c != ['0']:
            c.insert(0,'-')
        c = ''.join(c)
        return c
    

    高精度除

    模拟手算即可。

    def division(a:str,b:str,precision:int) -> str:
        minus_a = minus_b = False
        if a[0] == '-':
            minus_a = True
        if b[0] == '-':
            minus_b = True
        if minus_a and minus_b:
            return division(a[1:],b[1:],precision)
        elif minus_a and (not minus_b):
            return '-' + division(a[1:],b,precision)
        elif (not minus_a) and minus_b:
            return '-' + division(a,b[1:],precision)
        decimal_place_a = decimal_place_b = 0
        if '.' in a:
            decimal_place_a = len(a.split('.')[1])
        if '.' in b:
            decimal_place_b = len(b.split('.')[1])
        # 将字符串转化为整形
        num1 = a.replace('.', '')
        num2 = b.replace('.', '')
        if decimal_place_a > decimal_place_b:
            num2 += '0' * (decimal_place_a - decimal_place_b)
        elif decimal_place_a < decimal_place_b:
            num1 += '0' * (decimal_place_b - decimal_place_a)
        num1 = int(num1)
        num2 = int(num2)
        quotient = num1 // num2
        # 获取小数部分
        remainder = num1 % num2
        decimal_place = 0
        result = []
        while remainder != 0 and decimal_place < precision:
            remainder *= 10
            result.append(str(remainder // num2))
            remainder = remainder % num2
            decimal_place += 1
        # 将结果转化为字符串
        if len(result) != 0:
            result_str = ('.' + ''.join(result))
        else:
            result_str = ''
        return str(quotient) + result_str
    

    高精度乘方(指数为整数)

    实现很简单,但可以用快速幂优化。

    def power1(a:str,b:str,accuracy:int) -> str:
        if '.' in b:
            y1,y2,y3 = decimal_to_fraction(b)#res=a^b=a^(d+e/c)=a^d*(root(a,c))^e
            return multiply(power1(a,y2,accuracy),power1(root(a,y1,accuracy),y3,accuracy))
        elif '.' not in a:
            return str(pow(int(a),int(b)))
        if b[0] == '-':
            return division('1',power1(a,b[1:],accuracy),accuracy)
        if a[0] == '-':
            c = '-'
            if '.' in b:
                raise ValueError('power1')
            if minus(multiply(division(b,'2',0),'2'),b)=='0':
                c = ''
            return c+power1(a[1:],b,accuracy)
        bins = list(bin(int(b))[2:])
        times = len(bins)
        c = a
        if a == '0':
            if b == '0':
                return 'Error:0^0无意义'
            else:
                return '0'
        if b == '0':
            return '1'
        if a == '1':
            return '1'
        for i in range(1,times):
            c = multiply(c,c)
            if accuracy != -1:
                c = rounding_down(c,accuracy+(times-i+1)**(times-i))
            if bins[i] == '1':
                c = multiply(c,a)
        if accuracy != -1:
            c = rounding_down(c,accuracy)
        return c
    

    decimal_to_fraction函数

    一个衔接函数,作用是返回转分数后的 aa 的分母,aa 的整数部分,aa 的小数部分的分子。

    from fractions import Fraction
    
    def decimal_to_fraction(a):
        a = Fraction(a).limit_denominator(20)
        b = a.numerator
        c = a.denominator
        d = b//c
        e = b%c
        return str(c),str(d),str(e)#c:分母;d:[a];e:{a}
    

    高精度乘方(指数为有理数)

    二分法:(会TLE,可能是我常数没调好)

    def root(a,b,accuracy):
        if accuracy != 0:
            epsilon_max = '0.'+(accuracy-1)*'0'+'1'
        else:
            epsilon_max = '1'
        num = 0       #计算次数
        low = '0'  #下限
        high = a  #上限
        ans = division(plus(low,high),'2',accuracy+10)  #中点
        epsilon = '10'
        while not judge(epsilon,epsilon_max):
            num += 1
            buffer = power1(ans,b,-1)
            if buffer < a:
                low = ans
            else:
                high = ans
            ans = division(plus(low,high),'2',accuracy+num*num)
            epsilon = abs1(minus(power1(ans,b,-1),a))
        return ans
    

    牛顿迭代法(将问题转换为求xb=ax^b=a方程的解):

    def root(a:str,b:str,accuracy:int) -> str:
        #求power1(a,1/b)
        #x**b-y即函数f(x);b*x**(b-1)函数f(x)的导数
        x = '1'+len(a)*int(division('1',b,0))*'0' #初始值
        y = a
        num = 0 #迭代次数
        if accuracy != 0:
            epsilon_max = '0.'+(accuracy-1)*'0'+'1'
        else:
            epsilon_max = '1'
        epsilon = '100'
        while not judge(epsilon,epsilon_max):
            num += 1
            f_x = minus(power1(x,b,-1),y)
            f_x_ = multiply(b,power1(x,minus(b,'1'),-1))
            x = minus(x,division(f_x,f_x_,accuracy*2+num*num))
            epsilon = abs1(minus(power1(x,b,-1),y))
        x = rounding_down(x,accuracy+int(b)*10)
        return x
    

    后记

    将以上代码结合起来即为最终代码,中间有些简单的函数就不放了防止抄作业。以上代码均为作者手打,请勿抄袭借鉴还是可以的

    • -15
      @ 2024-3-6 15:18:44

      1

      • -15
        @ 2024-3-6 15:18:43

        1

        • -15
          @ 2024-3-6 12:17:41

          1

          • -15
            @ 2024-3-6 12:17:40

            1

            • -15
              @ 2024-3-6 12:17:16

              1

              • -15
                @ 2024-3-6 12:17:14

                1

                • -16
                  @ 2024-3-6 15:19:18

                  1

                  • -16
                    @ 2024-3-6 15:19:17

                    1

                    • 1

                    【求测试】【难题预警】a**b(加强版)

                    信息

                    ID
                    10
                    时间
                    1000ms
                    内存
                    256MiB
                    难度
                    9
                    标签
                    递交数
                    169
                    已通过
                    5
                    上传者