C (gcc), 82 байти
n;f(x,y,a,b)int*x,*y;{for(n=0;a;)--b&&*x*2-*y>y[1]?++y:(++b,--a,n+=abs(*x++-*y));}
Це сприймає дані як два цілих масиви та їх довжину (оскільки C не має можливості отримати їх довжину в іншому випадку). Це може бути показано, що він працює, O(a+b)
оскільки a
або b
зменшується на кожній ітерації циклу, яка закінчується при a
досягненні 0
(і b
не може бути зменшена нижче 0
).
Спробуйте в Інтернеті!
n; // define sum as an integer
f(x,y,a,b) // function taking two arrays and two lengths
int*x,*y; // use k&r style definitions to shorten function declaration
{
for(n=0; // initialize sum to 0
a;) // keep looping until x (the first array) runs out
// we'll decrement a/b every time we increment x/y respectively
--b&& // if y has ≥1 elements left (b>1, but decrements in-place)...
*x*2-*y>y[1]? // ... and x - y > [next y] - x, but rearranged for brevity...
++y: // increment y (we already decremented b earlier);
(++b, // otherwise, undo the in-place decrement of b from before...
--a,n+=abs(*x++-*y)) // decrement a instead, add |x-y| to n, and then increment x
;}
Деякі примітки:
Замість того, щоб індексувати масиви, примноження покажчиків та перенаправлення безпосередньо економить достатню кількість байтів, щоб воно було вартим ( *x
проти x[a]
і y[1]
проти y[b+1]
).
У --b&&
перевіряє стан для b>1
обхідним шляхом - якщо b
є 1
, то буде нульове значення. Оскільки це b
змінюється, нам не потрібно міняти його в першій гілці терміналу (яка просувається y
), але нам потрібно змінити його назад у другій (яка просувається x
).
Жодне return
твердження не потрібно, бо чорна магія. (Я думаю, що це тому, що останнім оцінюваним твердженням завжди буде n+=...
вираз, який використовує той же регістр, що і той, який використовується для повернення значень.)