ABC105 D - Candy Distribution
問題
https://atcoder.jp/contests/abc105/tasks/abc105_d
解法
解のパターンを以下の通り分割します。
- パターン1: 1番目の箱のみ使うパターン
- パターン2: 2番目の箱、および、必要ならば1番目の箱を使うパターン
- パターン3: 3番目の箱、および、必要ならば1, 2番目の箱を使うパターン
- ...
- パターンN: N番目の箱、および、必要ならば1, 2, ..., N-1番目の箱を使うパターン
上記のパターン分けは直和分割なので、最終的に求める解は上記の各パターンの解の和です。 パターンiの解をで表します
は簡単に求められます。 がMの倍数ならば、1, そうでなければ0です。
次に、 を求めます。
- がMの倍数か
- がMの倍数か
をチェックし、結果に応じて、0, 1, 2のいずれかの値になります。
を求めます。 同様に、3通りの計算を実施し、Mの倍数かチェックしてもよいのですが、そろそろ一般化も考えてみましょう。 この方法だと、 はi通りの計算が必要となり、計算量が大きすぎます。
ちょっと唐突ですが、 の先頭から何個かの項を除去し、Mの倍数にできないかを考えます。 をMで割った余りをRとします。 0, , のうち、余りがRであるものの個数が です。 余りがRであるものを数え上げるのが大変そうですが、先頭からk要素の和の余りをハッシュで記憶しておけば、一般の場合においても、ほぼ定数オーダーの計算で を計算できます。 (ハッシュの初期値は {0: 1} となる。ハッシュの各要素(k, v)は余りがkとなるものがv個あることを意味する)
最後に、上記のアルゴリズムの動作の具体例を書きます。 サンプル2で遊んでみます。
- 29%17=12はハッシュに含まれません。パターン1の解は0です。ハッシュに12を追加します。
- 更新後のハッシュ: {0: 1, 12: 1}
- ここまでの合計値: 12
- (12+7=19)%17=2はハッシュに含まれません。パターン2の解は0です。ハッシュに2を追加します。
- 更新後のハッシュ: {0: 1, 2: 1, 12: 1}
- ここまでの合計値: 2
- 2+5=7はハッシュに含まれません。パターン3の解は0です。ハッシュに7を追加します。
- 更新後のハッシュ: {0: 1, 2: 1, 7: 1, 12: 1}
- ここまでの合計値: 7
- 7+7=14はハッシュに含まれません。パターン4の解は0です。ハッシュに14を追加します。
- 更新後のハッシュ: {0: 1, 5: 1, 7: 1, 12: 1, 14: 1}
- ここまでの合計値: 14
- (14+9=23)%17=6はハッシュに含まれません。パターン5の解は0です。ハッシュに6を追加します。
- 更新後のハッシュ: {0: 1, 5: 1, 6: 1, 7: 1, 12: 1, 14: 1}
- ここまでの合計値: 6
- (6+51=57)%17=6はハッシュに含まれます。パターン6の解は1です。ハッシュに6を追加します(既に存在するので値を1から2に増やします)。
- 更新後のハッシュ: {0: 1, 5: 1, 6: 2, 7: 1, 12: 1, 14: 1}
- ここまでの合計値: 6
- 6+7=13はハッシュに含まれません。パターン7の解は0です。ハッシュに13を追加します。
- 更新後のハッシュ: {0: 1, 5: 1, 6: 2, 7: 1, 12: 1, 13: 0, 14: 1}
- ここまでの合計値: 13
- (13+13=26)%17=9はハッシュに含まれません。パターン8の解は0です。ハッシュに9を追加します。
- 更新後のハッシュ: {0: 1, 5: 1, 6: 2, 7: 1, 9: 1, 12: 1, 13: 0, 14: 1}
- ここまでの合計値: 9
- (9+8=17)%17=0はハッシュに含まれます。パターン9の解は1です。ハッシュに0を追加します。
- 更新後のハッシュ: {0: 2, 5: 1, 6: 2, 7: 1, 9: 1, 12: 1, 13: 0, 14: 1}
- ここまでの合計値: 0
- (0+55=55)%17=4はハッシュに含まれません。パターン10の解は0です。ハッシュに4を追加します。
- 更新後のハッシュ: {0: 1, 4: 1, 5: 1, 6: 2, 7: 1, 9: 1, 12: 1, 13: 0, 14: 1}
- ここまでの合計値: 4
- (4+42=46)%17=12はハッシュに含まれます。パターン11の解は1です。ハッシュに12を追加します。
- 更新後のハッシュ: {0: 1, 4: 1, 5: 1, 6: 2, 7: 1, 9: 1, 12: 2, 13: 0, 14: 1}
- ここまでの合計値: 12
- (12+9=21)%17=4はハッシュに含まれます。パターン12の解は1です。ハッシュに4を追加します。
- 更新後のハッシュ: {0: 1, 4: 2, 5: 1, 6: 2, 7: 1, 9: 1, 12: 2, 13: 0, 14: 1}
- ここまでの合計値: 4
- (4+81=85)%17=0はハッシュに含まれます。パターン13の解は2です。ハッシュに0を追加します。
- 更新後のハッシュ: {0: 2, 4: 2, 5: 1, 6: 2, 7: 1, 9: 1, 12: 2, 13: 0, 14: 1}
- ここまでの合計値: 0
以上より、各パターンの解を合計すると6を得ます。
ACしたコード
from collections import defaultdict N, M = map(int, input().split()) A = list(map(int, input().split())) acc = 0 s = defaultdict(int) s[0] = 1 ans = 0 for a in A: acc = (acc + a) % M ans += s[acc] s[acc] += 1 print(ans)