Pull to refresh

Comments 53

Вроде уравнение плоскости, которая проходит через центр координат, то есть нужны 2 любые точки чтобы однозначно определить все углы наклона.

Некоторые участники квеста пытались использовать эту схожесть))

Я к тому, что в этой задаче в теории можно пару раз случайно вызвать функцию, не придумывая специальные значения и алгоритмы, только лень решать.

P.S. Я не прав (алгебраически и геометрически нужно вроде три случайных вызова).

(алгебраически и геометрически нужно вроде три случайных вызова).

Не совсем случайных. Нужно ещё чтобы матрица получилась невырожденной (строки/столбцы были линейно независимы).

Да, вот только вам надо эти точки угадать. Просто передав какую-то точку вы получите расстояние до плоскости (растянутое в константу раз). И просто по двум точкам вы однозначно плоскость не найдете.

Задача мне не понравилась, из пальца высосана, а самодовольства море разливанное.

def magic(x: int, y: int, z: int) -> int:
    a = 1
    b = 2
    c = 3
    return a * x + b * y + c * z

s = magic("a", "b", "c")
print(f'a={s.count("a")}, b={s.count("b")}, c={s.count("c")}')

Без лоха и жизнь плоха.

Шаман Хакер!

А что, (x: int, y: int, z: int) -> int: - задние типов аргументов и возвращаемого значения вообще ничего не ограничивает в Питоне?

вообще ничего не ограничивает в Питоне?

Ага. :)

Можно даже так написать:

def magic(x: print('hi'), y: int, z: int) -> int:
    a = 256
    b = 512
    c = 1024
    return a * x + b * y + c * z

Ваш код не работает - падает с ошибкой. Точнее, работает или не работает в зависимости от значения констант.

А какие именно значения констант валят этот код? слишком большие?

слишком большие?

a = 10**19 для 64-битной системы. Для 32-битной 10**9, наверное.

10**19 не решится и методом из статьи. Там x = 10**38 и первое слагаемое переполнится в итоге.
upd: в питоне же длинная арифметика, да.

Это питон. Там длинная арифметика встроенная. Не упадет, если только там константы не по миллиону знаков.

Можно вот так тогда:

def magic(x: int, y: int, z: int) -> int:
    a = 10000000000000000000000
    b = 20000000000000000000000
    c = 30000000000000000000000
    return a * x + b * y + c * z


class Num(int):
    mul: int | None

    def __new__(cls, x, *args, **kwargs):
        instance = int.__new__(cls, x, *args, **kwargs)
        instance.mul = None
        return instance

    def __rmul__(self, other) -> int:
        self.mul = other
        return super().__mul__(other)


x = Num(1)
y = Num(1)
z = Num(1)

magic(x, y, z)
print(x.mul, y.mul, z.mul)

А если numpy или подобные либы есть, то можно не класс создавать, а матрицей прикинуться:

import numpy as np


def magic(x: int, y: int, z: int) -> int:
    a = 10000000000000000000000
    b = 20000000000000000000000
    c = 30000000000000000000000
    return a * x + b * y + c * z


X = np.array([[1, 0, 0]])
Y = np.array([[0, 1, 0]])
Z = np.array([[0, 0, 1]])

print(magic(X, Y, Z))

Вы бы хотя бы условие задачи прочитали. Функция принимает целые числа в качестве аргументов, так что ваше решение в корне неверно.

Это задача на программирование, с условием описанным конкретным кодом, на конкретном языке программирования.
Это решение запускается, и решает задачу, на мой читательский взгляд - с меньшим числом допущений, чем попытка угадать размерность константы, которая не указана в описании задачи или спецификаци функции.

Размерность констант может быть любой, в условии оговаривается то, что они явлются натуральными числами, то есть 1, 2, 3 и так далее. Решение, конечно, запускается, но оно вообще не оптимальное. Если константы будут достаточно большими, вычисление может занять очень много времени либо вообще выдаст MemoryError.

Как программист я Вас очень хорошо понимаю. Но как олимпиадник - нет, потому что про время вычисления в условии не оговаривается. Понимаю это уже рефлекс из опыта разработки, но раз это ограничение не оговорено, и это сферическая задача в вакууме, а не часть продакшн модуля - его нет.

как олимпиадник - нет

Согласен. Задача сформулирована не корректно, с точки зрения соревнований/конкурса. Что-то (ограничения) приходится додумывать.

Раньше в олимпиадном программировании всегда были ограничения и на память и на время. Решение прошло бы на хакерском квесте, но не на олимпиаде по математике или программированию.

мы приходим к тому-же недостаточно описанному условию, при каком-то наборе тестов и констант прошло бы, при каком-то нет...

В условии не говорится, что они являются натуральными. Это дополнительное ограничение вводится, когда хочется притянуть за уши возможность решения с двумя вызовами:

Оказывается, можно — при условии, что константы a, b и c являются натуральными числами.

Поэтому таким же образом, @longclaps может сказать: "Оказывается можно и за один - при условии, что константы в диапазоне от 0 до 10**19".

Нет, это решение отлично работет в питоне. Ваше решение тоже основано на тонкостях работы питона. Конкретно, на том, что там встроенная длинная арифметика. Если бы это был какой-нибудь C++ с 32-битными int-ами, то удачи вам получить назад число из 27 цифр.

Можно строки заменить на векторы: x = (1, 0, 0), y = (0, 1, 0), z = (0, 0, 1). Либо самому написать простенький класс, либо, например, воспользоваться numpy.

В квесте была проверка на тип int, такое решение не проходило

Ну это вообще на решение не тенет. А если у вас "черный ящик" с проверкой типов переданных аргументов?

Некоторое размышление сразу привели к тому, что нужно как-то разделить числа на разные интервалы порядков, не было только понятно как это сделать, без неоднозначности. А вот использование суммы неизвестных и исходя из этого использовать степени, вот это как раз любопытно, хотя после того как узнал, становится практически очевидным.

Самое забавное, что иногда такие задачи приходится решать. Но там есть известные ограничения на максимальное значение элементов.

после того как узнал, становится практически очевидным.

ИМХО это признак хорошей задачи.

Если прочитать условие задачи НЕ смотря на картинку, то не понятно что возвращает функция. Вот так у нас и пишут документацию )

0 вызовов:

from inspect import getsource


def magic(x: int, y: int, z: int) -> int:
    a = 256
    b = 512
    c = 1024
    return a * x + b * y + c * z


print(getsource(magic))

Не хватает кода для разбора (парсинга) кода функции, чтобы определить значения констант. :)

Допустим, так:

from inspect import getsource


def magic(x: int, y: int, z: int) -> int:
    a = 256
    b = 512
    c = 1024
    return a * x + b * y + c * z


def parse_var_vals(source_code: str) -> None:
    code_fragments = source_code.split('    ')
    func_vars = [fragment.strip() for fragment in code_fragments if ' = ' in fragment]
    vars_mapping = dict([var.split(' = ') for var in func_vars])

    print(', '.join(func_vars))
    print(vars_mapping)


if __name__ == '__main__':
    parse_var_vals(getsource(magic))

С помощью десятичного логарифма находим минимальную степень десяти, превышающую число total, которую запишем в переменную power

Непонятно, почему бы не воспользоваться тривиальным power = 1 + len(str(total))

А если не нравится, что для точных степеней десятки оно даст больше, чем нужно - ну можно отнять единичку.

Классная задача, заставила знатно попотеть конечно, но я с ней справился 👍

А где же разбор за один вызов magic()?

Если немного схитрить в том, что это всё же не чисто математическая задача, а задание на программирование, то можно и в один вызов, сохраняя все исходные требования к типам:

class MyInt(int):
    memory: list[tuple] = []

    def __rmul__(self, __value):
        return MyInt(__value)

    def __add__(self, __value):
        self.memory.append((self, __value))
        return MyInt(0)


def magic(x: int, y: int, z: int) -> int:
    a = 314
    b = 271828
    c = 69
    return a * x + b * y + c * z


if __name__ == '__main__':
    x_ = MyInt(0)
    y_ = MyInt(0)
    z_ = MyInt(0)
    assert isinstance(x_, int)
    assert isinstance(y_, int)
    assert isinstance(z_, int)

    result = magic(x=x_, y=y_, z=z_)
    assert isinstance(result, int)
    print(', '.join([str(j) for i in result.memory for j in i if j]))

Можно изящнее, но подход, думаю, понятен

Не знаю питон, но разве у инта нет ограничения на максимальный размер? И что будет если одна из переменных будет близка к этому ограничению?

В питоне - нет. Там встроенная длинная арифметика. Пока памяти хватает, числа могут быть сколь угодно большими.

  1. X=1, y=0, z=0

    Получаем значение a.

  2. X=0, y=a, z=1

    Получим число, остаток деления которого на а будет значение с, целая часть от этого деления будет b. Если остаток от деления равен 0, то b=с.

Это если c < a. А если больше? Вообще, вы тут x=0 передаете, т.ч можно любое достаточно большое число в качестве y передавать, не привязываясь к a. Вот только надо его заведомо больше c передать. И вот тут могут быть проблемы.

Простая задача. Можно и за один вызов функции решить)))

sum = magic(10**60, 10**30, 1)

a = round(sum / (10**60))

rest = sum - (a * (10**60))

b = round(rest / (10**30))

c = rest - (b * (10**30))

print(a,b,c)

 

 

 

А если b будет по порядку в 10**30 раз больше чем а? Тогда верного решения мы не получим

class int:

    def __init__(self, val) -> None:

        self.val = val

       

    def __rmul__(self, owner):

        st = owner * self.val

        return [st]

А если одно из чисел (a, b, c) порядка MAXINT/100?

В питоне длинная арифметика.

def magic(x: int, y: int, z: int) -> int:
    a = 256
    b = 512
    c = 1024
    return a * x + b * y + c * z


class A(int):
    def __rmul__(self, x):
        print(x)
        return self * x

print(magic(A(1), A(1), A(1)))

Коллега высказал идею, что если бы x, y, z были бы вещественные — можно было бы опознать a, b, c за один вызов magic(e², e, 1) перебором.

Сработает только при весьма маленьких целых a, b, c. Иначе никак не отличить {k/e, ke, 1} и {k, k, 1}, например. Если a,b,c должны быть целыми, то можно подобрать рациональное приближение e ~ m/n и ваш метод не отличит {n^2, m^2, 1} от {mn, mn, 1} из-за ошибок вычислений с плавающей точкой.

Помнится, такая задача, вместе с ещё двумя, попалась мне на очном собесе в майлРу в 2016. Все три уже были ранее решены на braingames.ru, и целых 20 минут я усиленно изображал работу мысли в поисках решения :)

Сколько же вы их перерешали? И сколько времени ушло на это?)

Там решил чуть более 500 паззлов. Сколько по времени - непонятно, бывал в основном набегами, в 10х гг. Сейчас обленился, не решаю)

Sign up to leave a comment.

Articles