先週、Facebook ハッカーカップのラウンド 1b に参加しました。
問題の 1 つは、基本的にヨセフス問題でした。
以前にジョセフス問題を離散数学の問題として研究したことがあるので、基本的に再帰を取得する方法を理解しています。
f(n,k) = (f(n-1,k) + k) mod n, with f(1,k) = 0
しかし、n の最大値が 10^12 だったので、Facebook Hacker Cup ではうまくいきませんでした。k の最大値は 10^4 でした。
ウィキペディアでは、k が小さく、n が大きい場合のアプローチについて言及しています。基本的に、1 回のラウンドから人を削除してから、番号を付け直します。しかし、それはあまり説明されておらず、なぜ再番号付けが機能するのか理解できません。
ソリューションのサンプル作業ソース コードを見ましたが、最後の部分がまだわかりません。
long long joseph (long long n,long long k) {
if (n==1LL) return 0LL;
if (k==1LL) return n-1LL;
if (k>n) return (joseph(n-1LL,k)+k)%n;
long long cnt=n/k;
long long res=joseph(n-cnt,k);
res-=n%k;
if (res<0LL) res+=n;
else res+=res/(k-1LL);
return res;
}
私が本当に理解していないのは、res-=n%k
(およびその後の行)から始まる部分です。それが結果を調整する方法であることをどのように導き出しますか?
誰かがこれがどのように導出されたかの背後にある理由を示すことができますか? またはそれを派生させるリンクですか?(UVA やトップコーダー フォーラムに関する情報は見つかりませんでした)