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));}
これは、2つの整数配列とその長さとして入力を受け取ります(それ以外の場合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
vs x[a]
およびy[1]
vs y[b+1]
)。
--b&&
以下のための条件をチェックb>1
遠回しで-場合b
で1
、それがゼロと評価されます。これはを変更するのでb
、3進の最初のブランチ(これはy
)で変更する必要はありませんが、2番目のブランチ()で元に戻す必要がありx
ます。
return
黒魔術なので、文は必要ありません。(私が考える評価されるべき最後の文は常になりますので、それはだn+=...
、戻り値のために使用されるものと同じレジスタを使用する表現、。)