最初の溶液:AおよびBはそれぞれ、幸せ算出Nシフト値の全ての組み合わせについて、幸せ値> = Hの組み合わせのために、そして剛毛とSETBに格納されています。ハッピー値> = H、Bの組み合わせ:iは、I-SETBの論理和で見つけることができ、各剛毛列挙組み合わせ(1 << N)Iの組み合わせを示すJ -1を、組み合わせJ:幸せ値> = H、AおよびBを満たすNシフトの組み合わせは、デューティに少なくとも1人を有します。(原理の使用は、式中、iは場合| J =(1 << N) - 1、次いでJスーパーセットKであり、満足I | K =(1 << N)-1)、SOS DPによって計算されますスーパーセットの番号の組み合わせ。
注意:2次元配列numのDPは、ここでは2次元、理解を容易にするため、1次元配列のための再帰関係を最適化すること。
より詳細な記事がありSOS DP、約ます:http://codeforces.com/blog/entry/45223
違いは、物品が、そこのスーパーセット(親セット)を探しているの組み合わせです、と記事はサブセット(サブセット)の組み合わせ(セット)を探して導入されることです。その固有のアイデアのスーパーセットまたはサブセットは、同じであるかどうか:例えば、101010111は、4番目のビットが0である場合、この組み合わせの4スーパーセットをビット0または1であってもよく、ビット3が1である、のその後組み合わせスーパーセット番号3は1つだけであることができます。(反しサブセットは、この組み合わせのサブセットのみが4ビット0、ビット3であり、サブセットがあってもよい0または1)。
「私は異なるビット前に、同一のハイレベル、」NUM [I] [マスク]サブセットの数組合せマスクです。
1つの インポートjava.util.Scanner。 2 インポートはjava.util.HashSet。 3 パブリック クラス GCJ_KI2019G_C5 { // SOS DP 4 パブリック 静的 ボイドメイン(文字列[]引数){ 5 =スキャナ新しいスキャナ(System.in)。 6 INT T = in.nextInt()。 7 のための(int型 ; CAS <= T; CAS = 1 CAS ++ ){ 8 INT N = in.nextInt()。 9 長い時間= in.nextLong()。 10 長いです[] = 新しい 長い[N]。 11 長い [] B = 新しい 長い[N]。 12 長いスマ= 0L。 長い SUMB = 0L ; 13 のために(int型 i = 0; iがN <; Iは++ ){ 14 [I] = in.nextLong()。 15 スマ+は= [I]。 16 } 17 のための(int型 ; iがn <I ++は、I = 0 ){ 18件の B [I] = in.nextLong()。 19 SUMBは+ = B [i]は、 20 } 21 であれば(SUMA <H || SUMB < H){ 22 のSystem.out.println( "ケース#" + CAS + ":" +0 )。 23 続け; 24 } 25 26 HashSetの<整数>セタ= 新しい HashSetの<> (); 27 RECUR(0、H、0L、0 、剛毛)。 28 HashSetの<整数> SETB = 新しい HashSetの<> (); 29 RECUR(B、0、H、0L、0 、SETB)。 30 31 のint [] [] NUM = 新しい INT [N + 1] [1 <<N]。 32 INT X =(1個の<< N) - 1 。 33 のための(int型:SETB V) 34 NUM [0] [V] = 1 。 35 36 のために(int型、iがn = <; I = 1 iは++){ // SOS DP 37 のための(int型マスク= 0;マスク<= xと;マスク++ ){ 38 NUM [I] [マスク] = NUM [1- 1 ] [マスク]。 39 であれば((マスク&(1 <<(I-1)))== 0 ) 40 NUM [I] [マスク] + = NUM [I-1] [マスク| 1 <<(I-1 )]。 41 } 42 } 43 44 長い ANS = 0リットル。 45 のための(int型V:セタ){ 46 ANS + = NUM [N] [X - V]。 47 } 48 のSystem.out.println( "ケース#" + CAS + ":" + ANS)。 49 } 50 } 51 52 静的 ボイド(再発長い [] ARR、INT P、長い時間、長い ACCU、INTビットマスク、HashSetの<整数> セット){ 53 もし(P == arr.length){ 54 であれば(ACCU> = H){ 55 set.add(ビットマスク)。 56 } 57 リターン。 58 } 59 RECUR(ARR、P + 1 、H、ACCU、ビットマスクセット)。 60 RECUR(ARR、P + 1、H、ACCU + ARR [P]、ビットマスク|(1 << P)、設定されました)。 61 } 62 }
*******************************************分割ライン***** ******************************************
第二の溶液:
n個のシフトは、2つのセクション、0〜N / 2、N / 2 + 1〜N-1に分割します
各セクションの複数を形成する幸せな値になり、最初の段落でハッピー値対に対して、第二段落の幸せ値ペア存在する場合、pair1.first + pair2.first> = Hおよびpair1.second + pair2.second>を満たすために= hが、これは有効な解決策です。
ペアの最初の段落のために、セグメントツリーを使用して迅速に上記の条件を満足する一対の第二段落の数を知ることができます。
インポートjava.util.Scanner; 輸入はjava.util.ArrayList; 輸入java.util.Collections。 パブリッククラスソリューション{ パブリック静的無効メイン(文字列[] args){ =新しいスキャナ(System.in)でスキャナ。 INT T = in.nextInt()。 (INT CAS = 1; CAS <= T; CAS ++)のために{ INT、N = in.nextInt()。 INT H = in.nextInt()。 長い[] =新しい長い[N]。 長い[] B =新しい長い[N]。 長いUMA = 0L; 長軸= 0L。 以下のために(INT i = 0; iがn <; iは++){ [I] = in.nextLong()。 スマ+は= [I]。 } 以下のために(INT i = 0; iがn <; iは++){ B [I] = in.nextLong()。 SUMB + = B [i]は、 } IF(SUMA <H || SUMB <H){ System.out.println( "ケース#" + CAS + ":" +0)。 持続する; } ArrayListの<ペア>リスト1 =新しいArrayListを<>(); 再発(B、0、N / 2,0L、0L、LIST1、H)。 ArrayListの<ペア>リスト2 =新しいArrayListを<>(); 再発(A、B、N / 2 + 1、N-1,0L、0L、LIST2、H)。 Collections.sort(LIST1)。 Collections.sort(LIST2)。 SegTreeツリー=新しいSegTree(0、H)。 長年= 0; INT P = list2.size() - 1; {(LIST1ペアのペア)のために 一方、(P> = 0 && list2.get(P).fir> = H - pair.fir){ tree.add(list2.get(P).SEC)。 P--; } ANS + = tree.get(H - pair.sec、H)。 } System.out.println( "ケース#" + CAS + ":" + ANS)。 } } 静的クラスSegTree { ハイ、ローINT。 SegTreeは、右から左。 int型の合計= 0; (int型B INT)公衆SegTree { 低=; 高い= Bと、 } 公共ボイドアドオン(int型V){ 合計++; (低==高)であれば 返します。 INT、M =ロー+(高 - 低)/ 2。 IF(V <= M){ (左==ヌル)の場合 左=新しいSegTree(ロー、M)。 left.add(V); } 他の{ もし(右== nullの) 右=新しいSegTree(M + 1、高)。 right.add(V); } } 公共int型のget(int型bをint型){ IF(<=低&&のB> =高) 合計を返します。 IF(>高|| Bの<低いです) 0を返します。 int型のA = 0; (左!= null)の場合 RES = left.get(B) (右!= null)の場合 RES + = right.get(B) 解像度を返します。 } } 静的クラス対が実装匹敵<ペア> { int型モミ、秒。 公共のペア(INT、INT b)は{ モミ= A; 秒= B。 } 公共のintのcompareTo(ペアのペア){ Integer.compare(モミ、pair.fir)を返します。 } } 静的ボイドは、(長い[]、長い[] B、INT P、INT端、長いaccuA、長いaccuB、のArrayList <ペア>リストを、INT H)再発{ もし(P>端){ list.add(新しいペア((INT)Math.min(H、accuA)、(INT)Math.min(H、accuB)))。 返します。 } 再発(A、B、P + 1、終わり、accuA + [P]、accuB、リスト、H)。 再発(A、B、P + 1、終わり、accuA、accuB + B [P]、リスト、H)。 (A、B、P + 1、終わり、accuA + [P]、accuB + bの[P]、リスト、H)再発します。 } }