Блог пользователя MathLimitExceeded

Автор MathLimitExceeded, история, 10 лет назад, По-английски

Hi

I am solving a problem that is conceptually simple.

Given an integer x, such that 1 ≤ x ≤ 1017, check if v = 5x2 + 2x + 1 is a perfect square. I have solved this using Big Integers and long doubles in C++ (with a binary search to find the root) and used PyPy to get it accepted in Python but I did not receive satisfaction in solving it this way.

Also, __int128 do not work on SPOJ for some reason :/

I think Big Integer may be an overkill for such a problem and the uncertainty with floating point precision is never re-assuring. Hence, my question is, is there any way to solve this problem without Big Integers or long doubles in C++?

Thanks

  • Проголосовать: нравится
  • +12
  • Проголосовать: не нравится

»
10 лет назад, скрыть # |
 
Проголосовать: нравится +11 Проголосовать: не нравится

, i.e. x + 1, 2x and y should form a Pythagorean triple. Then use the fact that the Pythagorean triple is always expressible as (2ab, a2 - b2, a2 + b2) for some integers a and b, and this will allow you to write the solution that uses only 64-bit data types.

»
10 лет назад, скрыть # |
← Rev. 2  
Проголосовать: нравится +8 Проголосовать: не нравится

Try this.
Maybe for large numbers there exists a counterexample, and you must use a random prime numbers that's still less than 109.

»
10 лет назад, скрыть # |
 
Проголосовать: нравится +11 Проголосовать: не нравится

FWIW I'd go with long doubles for this — it's not hard to prove that the precision is enough. If we compute "y = sqrt(5*x*x + 2*x + 1)" as a long double, we get a ~57-bit number, and the error should be low (at most a 1-ulp error resulting from the large multiplication, 1 from the addition, and 1 from the sqrt, and addition and sqrt both give additive errors). The mantissa of long doubles is 64 bits, so we'll always be within 2^(57 — 64) * 3 = ~0.02 of the right answer. So if v is a perfect square, "z = (long long)round(y)" will be correct.

Then just check that "z*z == 5*x*x + 2*x + 1" modulo distinct primes with large enough product, per CRT.