bitDPメニューのサムネイル
O(3^N) のビット DP Java編(paizaランク S 相当)

問題にチャレンジして、ユーザー同士で解答を教え合ったり、コードを公開してみよう!

問題

下記の問題をプログラミングしてみよう!

説明



step1 では、動的計画法の遷移は以下のようになっており、時間計算量は O(2^N × 2^N) = O(4^N) 時間でした。

for s = 0 to 2^N - 1:
for t = 0 to 2^N - 1:
if t が s の部分集合なら:
dp[s] = max(dp[s], dp[(s と t の差集合)] + Z[t])


実は、もっと効率的に実装することができます。
この遷移は、集合 s の部分集合 t を用いて遷移しています。
集合 s = {1,3} = 101 の部分集合 t = 101, 100, 001, 000 です。
ここで、以下の 2 点がわかります。
・集合 s で 1 の桁は、部分集合 t で 0 か 1
・集合 s で 0 の桁は、部分集合 t で必ず 0
つまり、集合 s の部分集合を列挙するには、s の 1 の部分の 0, 1 の組合せを全通り列挙すればよいです。
この考えに基づき、以下の方法を実装することで、効率的に部分集合を列挙できます。

t = s
while t >= 0:
t &= s # s と t の論理積をとる
# 部分集合 t に対する処理
t -= 1


これを用いてより高速な方法で問題を解いてみましょう。

問題



この問題は前回の問題と N の制約のみが異なります。


paiza 大学院には N 人の学生がいます。
人 i には整数 A_i が割り当てられています。
いまから N 人を 1 つ以上のいくつかのグループにわけます。
グループ j に属している人の集合を S_j = {i_1, i_2, ... , i_{c_j}} とします。ここで、c_j はグループ j の人数を表します。
このとき、グループ j の相性は Z_{S_j} := (A_{i_1} XOR A_{i_2} XOR ... XOR A_{i_{c_j}}) × c_j として定義されます。
どの人も必ず 1 つのグループに属さなければなりません。
すべての人のグループ分けが終わった後、各グループの相性の総和 Σ Z_{S_j} の最大値を求めてください。

入力される値

入力は以下のフォーマットで与えられます。

N
A_1 A_2 ... A_N

・ 1 行目には、学生の数を表す整数 N が与えられます。
・ 2 行目には、数列 A が与えられます。
・ 入力は合計で 2 行からなり、入力値最終行の末尾に改行が 1 つ入ります。


入力値最終行の末尾に改行が1つ入ります。
文字列は標準入力から渡されます。 標準入力からの値取得方法はこちらをご確認ください
期待する出力

各グループの相性の総和 Σ Z_j の最大値を求めてください。
末尾に改行を入れ、余計な文字、空行を含んではいけません。

条件

すべてのテストケースにおいて、以下の条件をみたします。

・ 1 ≦ N ≦ 15
・ 0 ≦ A_i < 2^50

入力例1

4
1 2 3 4

出力例1

24

入力例2

3
7 4 3

出力例2

21

入力例3

15
707653749851665 486655667345044 763127172605705 342043409486452 438238760474754 449584922329928 634943318136335 686770025079584 195674230421279 526867366425406 415660722668925 25291999775630 473566887008639 861671609720570 615523627674408

出力例3

16824523972853352

問題一覧へ戻る

  1. paizaラーニングトップ
  2. レベルアップ問題集
  3. bitDPメニュー(言語選択)
  4. 問題一覧 Java編
  5. O(3^N) のビット DP Java編
ページの先頭へ戻る