問題
https://community.topcoder.com/stat?c=problem_statement&pm=14362
n要素の配列bが与えられる
この時、以下の条件を満たすn要素の配列aが存在するか判定せよ
- 全ての要素はバラバラ(distinct)である
- 全ての要素は1より大きい
- a[i]^b[i]はp[i]で割り切れる
(p[i] = a[1]*...*a[i-1]*a[i+1]*...*a[n-1])
存在するなら"Possible"しないなら"Impossible"
2 <= n <= 50
1 <= b[i] <= 10
帰納的考察(TwitterやEditorial見た)
1. b[i]がとても小さいのが気になる
2. とりあえず、配列bは昇順ソートしても答えに影響しないのでする
3. …でどうするん???
――壁――
ai*(bi+1) >= sum(a) for 0 <= i <= n-1
— roiti (@roiti46) 2016年8月18日
はわかったけどそこからどうすればいいかわからんかった
4. Twitterまとめ見てたらこんな一節が
5. 圧倒的地頭力
6. Editorialにも同じようなことが書いてある
https://apps.topcoder.com/wiki/display/tc/SRM+697#DivisibleSetDiv1
7. これが分かってもまだ解けない鬼畜仕様
8. この数式を前提としてkmjpさんの解答見たら分かった
9. kmjpさんの解法では全探索してる
10. 「bを降順ソートしておくと、答えのaは昇順になる」が満たされるっぽい
11. これを元にa[i]を小さい方から順に決定していく
12. 答えがあれば10^6以内に解が見つかるみたい
実装
int n; int a[50]; struct DivisibleSetDiv1 { string isPossible(vector<int> b) { n = b.size(); sort(b.begin(), b.end(), greater<int>()); int sum = 0; rep(i, 0, n) a[i] = i + 2, sum += a[i]; rep(loop, 0, 1000000) { bool ok = true; rep(i, 0, n) { if (a[i] * (b[i] + 1) < sum) { rep(j, i, n) a[j]++, sum++; ok = false; break; } } if (ok) return "Possible"; } return "Impossible"; } };