結果
問題 | No.1743 Permutation Code |
ユーザー | whileTrue398 |
提出日時 | 2021-11-30 10:33:56 |
言語 | Java21 (openjdk 21) |
結果 |
TLE
|
実行時間 | - |
コード長 | 12,716 bytes |
コンパイル時間 | 2,750 ms |
コンパイル使用メモリ | 95,444 KB |
実行使用メモリ | 65,612 KB |
最終ジャッジ日時 | 2024-07-03 03:41:26 |
合計ジャッジ時間 | 14,462 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 101 ms
40,244 KB |
testcase_01 | AC | 122 ms
40,784 KB |
testcase_02 | AC | 114 ms
40,392 KB |
testcase_03 | AC | 121 ms
40,692 KB |
testcase_04 | AC | 199 ms
44,936 KB |
testcase_05 | AC | 133 ms
40,540 KB |
testcase_06 | AC | 305 ms
49,380 KB |
testcase_07 | TLE | - |
testcase_08 | -- | - |
testcase_09 | -- | - |
testcase_10 | -- | - |
testcase_11 | -- | - |
testcase_12 | -- | - |
testcase_13 | -- | - |
testcase_14 | -- | - |
testcase_15 | -- | - |
testcase_16 | -- | - |
testcase_17 | -- | - |
testcase_18 | -- | - |
testcase_19 | -- | - |
testcase_20 | -- | - |
testcase_21 | -- | - |
testcase_22 | -- | - |
testcase_23 | -- | - |
testcase_24 | -- | - |
testcase_25 | -- | - |
testcase_26 | -- | - |
testcase_27 | -- | - |
testcase_28 | -- | - |
testcase_29 | -- | - |
ソースコード
import java.io.IOException; import java.io.InputStream; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Queue; public class Main { static final int inf = Integer.MAX_VALUE / 2; static StringBuilder out = new StringBuilder(); static boolean[] dig; static int n, ln; static int[] imos; static int[][] order; static Map<Long, Integer> zeromap = new HashMap<>(); static List<Queue<Integer>> index = new ArrayList<>(); static SegmentTree st; public static void main(String[] args) { FastScanner sc = new FastScanner(System.in); /* * 枝刈り法をベースに解く * 0の位置をもとに0の多い数から順列に当てはめていく * その位置のbitをまだ使ってないかは区間和のセグ木で判定する * その区間の和が0ならまだ使ってないので使い、区間の値を全て1にする。 */ //入力を桁ごとにboolで受け取る { char[] c = sc.next().toCharArray(); n = c.length; //最後に番兵をつける dig = new boolean[n+1]; dig[n] = true; imos = new int[n+1]; for(int i = 0; i < n; i++) { dig[i] = c[i] == '1'; imos[i+1] = imos[i] + (dig[i] ? 1 : 0); } } // ln =順列の最大値+1 { int cnt = 0; for(ln = 1; cnt < n; ln++) { int ii = ln; while(ii > 0) { ii >>= 1; cnt++; } } } //探索する優先順位 order = new int[ln-1][3]; for(int i = 0; i+1 < ln; i++) { int maxConsecutiveZeros = 0; int ConsecutiveZeros = 0; int cntZeros = 0; int ii = i+1; while(ii > 0) { if((1&ii) == 1) { maxConsecutiveZeros = Math.max(ConsecutiveZeros, maxConsecutiveZeros); ConsecutiveZeros = 0; }else { ConsecutiveZeros++; cntZeros++; } ii >>= 1; } order[i][0] = i+1; order[i][1] = cntZeros; order[i][2] = maxConsecutiveZeros; } //連続した0の数が多いほど優先する //それが同じなら0の数が多いほど優先する //それも同じならその数の大きい順 Arrays.sort(order, (x, y) -> Integer.compare(y[0], x[0])); Arrays.sort(order, (x, y) -> Integer.compare(y[1], x[1])); Arrays.sort(order, (x, y) -> Integer.compare(y[2], x[2])); //すべての0始まり0終わりのパターン(正規表現で'(0+1+)*0+')を抽出し、連続した値に変換するmapを作る int mapsize = 0; { for(int i = 1; i < ln; i++){ int ii = i; while((1&ii) == 1) ii >>= 1; if(ii == 0) continue; long key = 0; int cntz = 0; int cnto = 0; while((1 & ii) == 0){ ii >>= 1; key++; } while((1 & ii) == 1){ ii >>= 1; cnto++; } long v = 16; while(ii > 0){ while((1 & ii) == 0){ ii >>= 1; cntz++; } key += cnto*v; v <<= 4; key += cntz*v; v <<= 4; cntz = 0; cnto = 0; while((1 & ii) == 1){ ii >>= 1; cnto++; } } if(!zeromap.containsKey(key)) zeromap.put(key, mapsize++); } } // System.out.println("zeromap : "); // for(long key : zeromap.keySet()) { // // Deque<Integer> kl = new ArrayDeque<>(); // String rekey = key + "(1"; // // long tkey = key; // while(tkey > 0) { // kl.push((int)(tkey%16)); // tkey /= 16; // } // // boolean odd = false; // while(!kl.isEmpty()) { // int tmp = kl.pollFirst(); // for(int i = 0; i < tmp; i++) // rekey += odd ? '1' : '0'; // // odd = !odd; // } // // rekey += ") -> " + zeromap.get(key); // // System.out.println(rekey); // } // System.out.println(""); //入力に出てくる //直前に1のある0から始まり、直後に1のある0で終わるパターン //(正規表現で'10+(1+0*)*1')の位置を記録 for(int i = 0; i < mapsize; i++) index.add(new ArrayDeque<>()); for(int l = 1; l < n; l++){ if(dig[l-1] != true || dig[l] != false) continue; long key = 0; boolean prev = false; int cntz = 0; int cnto = 0; long now = 1; for(int r = l; r < n; r++){ now <<= 1; if(dig[r]) now++; if(now >= ln) break; if(prev != dig[r]) { if(dig[r]) cnto = 0; else cntz = 0; prev = dig[r]; } if(dig[r]){ cnto++; }else{ cntz++; if(dig[r+1] == true) { key <<= 4; key += cnto; key <<= 4; key += cntz; index.get(zeromap.get(key)).add(l); } } } } // System.out.println("index:"); // for(int i = 0; i < index.size(); i++) { // String str = "" + i + " ->"; // int qs = index.get(i).size(); // for(int j = 0; j < qs; j++) { // int t = index.get(i).poll(); // str += " " + t; // index.get(i).add(t); // } // System.out.println(str); // } // System.out.println(""); st = new SegmentTree(n); if(!dfs(0)) { System.out.println(-1); return; } for(int i = 0; i < n; i++) { st.getsum(i, i+1); } Arrays.sort(order, (x, y) -> Integer.compare(x[1], y[1])); String ans = ""; String anss = ""; int indcnt = 0; for(int i = 0; i < order.length; i++) { out.append(order[i][0] + " "); String an = ""; int tmp = order[i][0]; int cnt = 0; while(tmp > 0) { if((1&tmp) == 1) an = '1' + an; else an = '0' + an; tmp >>= 1; cnt++; } anss += an; an = "(" + order[i][0] + ":" + indcnt + ")" + an; indcnt += cnt; ans += an; } // System.out.println(anss); // System.out.println(ans); System.out.println(out); } private static boolean dfs(int ind) { if(ind == order.length) { return true; } long key = 0; int lo = 0; int bitSize = 0; int bitCount = 0; int p = order[ind][0]; while((1&p) == 1) { p >>= 1; bitSize++; bitCount++; } if(p > 0) { int cntz = 0; int cnto = 0; while((1 & p) == 0){ p >>= 1; bitSize++; key++; } while((1 & p) == 1){ p >>= 1; bitSize++; bitCount++; cnto++; lo++; } long v = 16; while(p > 0){ while((1 & p) == 0){ p >>= 1; bitSize++; cntz++; } key += cnto*v; v <<= 4; key += cntz*v; v <<= 4; cntz = 0; cnto = 0; lo = 0; while((1 & p) == 1){ p >>= 1; bitSize++; bitCount++; cnto++; lo++; } } } // String str = order[ind][0] + "(" + Integer.toString(order[ind][0], 2) + ") key=" + key; // System.out.println(str); //二進数表記で0が含まれていない場合 if(key == 0) { for(int i = 0; i < n; i++) { if(i+bitSize > n) continue; if(!dig[i+bitSize]) continue; if(imos[i+bitSize] - imos[i] != bitSize) continue; if(st.getsum(i, i+bitSize) == 0) { st.set(i, i+bitSize, 1); order[ind][1] = i; if(dfs(ind+1)) return true; st.set(i, i+bitSize, 0); } } }else { int inkey = zeromap.get(key); int qsize = index.get(inkey).size(); for(int i = 0; i < qsize; i++) { int tmp = index.get(inkey).poll(); int l = tmp-lo; int r = l+bitSize-1; if(l >= 0 && r < n) if(dig[r+1]) if(imos[r+1] - imos[l] == bitCount) if(st.getsum(l, r+1) == 0) { st.set(l, r+1, 1); order[ind][1] = l; if(dfs(ind+1)) return true; st.set(l, r+1, 0); } index.get(inkey).add(tmp); } } return false; } } class SegmentTree { private int n; int[] node; SegmentTree(int size){ n = 1; while(n < size) n *= 2; node = new int[2*n-1]; } void set(int a, int b, int x){ set(a, b, x, 0, 0, -1); } private void set(int a, int b, int x, int k, int l, int r) { if(r < 0) r = n; if(b <= l || r <= a) return; if(l+1 == r) { node[k] = x; }else { set(a, b, x, 2*k+1, l, (l+r)/2); set(a, b, x, 2*k+2, (l+r)/2, r); node[k] = node[2*k+1] + node[2*k+2]; } } int getsum(int a, int b) { return getsum(a, b, 0, 0, -1); } private int getsum(int a, int b, int k, int l, int r) { if(r < 0) r = n; if(b <= l || r <= a) return 0; if(a <= l && r <= b) return node[k]; int vl = getsum(a, b, 2*k+1, l, (l+r)/2); int vr = getsum(a, b, 2*k+2, (l+r)/2, r); return vl + vr; } } //class SegmentTree { // private int n; // int[] node, lazy; // int inf = Integer.MAX_VALUE/2; // // // SegmentTree(int size){ // n = 1; // while(n < size) // n *= 2; // // node = new int[n*2-1]; // lazy = new int[n*2-1]; // // Arrays.fill(lazy, inf); // } // // private void eval(int k, int l, int r) { // if(lazy[k] != inf) { // node[k] = lazy[k]; // // if(l+1 < r) { // lazy[2*k+1] += lazy[k] /2; // lazy[2*k+2] += lazy[k] /2; // } // // lazy[k] = inf; // } // } // // void set(int a, int b, int x) { // set(a, b, x, 0, 0, -1); // } // private void set(int a, int b, int x, int k, int l, int r) { // if(r < 0) // r = n; // // eval(k, l, r); // // if(b <= l || r <= a) // return; // // if(a <= l && r <= b) { // lazy[k] = (r-l)*x; // eval(k, l, r); // }else { // set(a, b, x, 2*k+1, l, (l+r)/2); // set(a, b, x, 2*k+2, (l+r)/2, r); // node[k] = node[2*k+1] + node[2*k+2]; // } // // // } // // int getsum(int a, int b) { // return getsum(a, b, 0, 0, -1); // } // private int getsum(int a, int b, int k, int l, int r) { // if(r < 0) // r = n; // if(b <= l || r <= a) // return 0; // // eval(k, l, r); // if(a <= l && r <= b) // return node[k]; // // int vl = getsum(a, b, 2*k+1, l, (l+r)/2); // int vr = getsum(a, b, 2*k+2, (l+r)/2, r); // // return vl+vr; // } //} class FastScanner { private final InputStream in = System.in; private final byte[] buffer = new byte[1024]; private int ptr = 0; private int buflen = 0; public FastScanner(InputStream in2) { // TODO 自動生成されたコンストラクター・スタブ } private boolean hasNextByte() { if (ptr < buflen) { return true; }else{ ptr = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (buflen <= 0) { return false; } } return true; } private int readByte() { if (hasNextByte()) return buffer[ptr++]; else return -1;} private static boolean isPrintableChar(int c) { return 33 <= c && c <= 126;} public boolean hasNext() { while(hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++; return hasNextByte();} public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = readByte(); while(isPrintableChar(b)) { sb.appendCodePoint(b); b = readByte(); } return sb.toString(); } public long nextLong() { if (!hasNext()) throw new NoSuchElementException(); long n = 0; boolean minus = false; int b = readByte(); if (b == '-') { minus = true; b = readByte(); } if (b < '0' || '9' < b) { throw new NumberFormatException(); } while(true){ if ('0' <= b && b <= '9') { n *= 10; n += b - '0'; }else if(b == -1 || !isPrintableChar(b)){ return minus ? -n : n; }else{ throw new NumberFormatException(); } b = readByte(); } } public int nextInt() { long nl = nextLong(); if (nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE) throw new NumberFormatException(); return (int) nl; } public double nextDouble() { return Double.parseDouble(next());} }