Codecraft-17 and Codeforces Round #391 (Div. 1 + Div. 2, combined) D. Felicity's Big Secret Revealed
問題
http://codeforces.com/contest/757/problem/D
0と1からなるn文字の文字列が与えられます。この文字列の好きな位置(先頭や末尾も含むN+1個)に仕切りを入れることができます。仕切りはいくつ入れても構いませんが、同じ位置に2個以上入れることはできません。仕切りを入れ終わったら、仕切りに挟まれている数字を10進数になおし、setに入れます。setの最大の数字をmとした時に、setに1〜mが全て含まれているような仕切りの入れ方をvalidとします。validな仕切りの入れ方をmod 1e9+7 で答えてください。
解法
nが75以下なので、mは最大でも20であることが分かります。
次のようなbitDPを考えます。
dp[pos][status] := pos文字目まで見た時に、[1, 20] の数字を含む状態のbitが status であるような組合せ
どこから始めても良いので初期状態は dp[i][0]=1 (0<=i
コード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class D { private final int MOD = (int) (1e9 + 7); private void solve(FastScanner in, PrintWriter out) { int N = in.nextInt(); String S = in.next(); int M = 1 << 20; int[][] dp = new int[N + 1][M]; for (int pos = 0; pos < N; pos++) { dp[pos][0] = 1; } for (int pos = 0; pos < N; pos++) { int cur = 0; for (int end = pos + 1; end <= N; end++) { cur = cur * 2 + (S.charAt(end - 1) - '0'); if (cur > 20) break; if (cur == 0) continue; for (int state = 0; state < M; state++) { int next = state | (1 << (cur - 1)); dp[end][next] += dp[pos][state]; dp[end][next] %= MOD; } } } long ans = 0; for (int end = 0; end <= N; end++) { for (int h = 1; h <= 20; h++) { int state = (1 << h) - 1; ans += dp[end][state]; ans %= MOD; } } out.println(ans); } public static void main(String[] args) { FastScanner in = new FastScanner(); PrintWriter out = new PrintWriter(System.out); new D().solve(in, out); out.close(); } private static class FastScanner { private final InputStream in = System.in; private final byte[] buffer = new byte[1024]; private int ptr = 0; private int bufferLength = 0; private boolean hasNextByte() { if (ptr < bufferLength) { return true; } else { ptr = 0; try { bufferLength = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (bufferLength <= 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; } private void skipUnprintable() { while (hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++; } boolean hasNext() { skipUnprintable(); 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(); } 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(); } } double nextDouble() { return Double.parseDouble(next()); } double[] nextDoubleArray(int n) { double[] array = new double[n]; for (int i = 0; i < n; i++) { array[i] = nextDouble(); } return array; } double[][] nextDoubleMap(int n, int m) { double[][] map = new double[n][]; for (int i = 0; i < n; i++) { map[i] = nextDoubleArray(m); } return map; } public int nextInt() { return (int) nextLong(); } public int[] nextIntArray(int n) { int[] array = new int[n]; for (int i = 0; i < n; i++) array[i] = nextInt(); return array; } public long[] nextLongArray(int n) { long[] array = new long[n]; for (int i = 0; i < n; i++) array[i] = nextLong(); return array; } public String[] nextStringArray(int n) { String[] array = new String[n]; for (int i = 0; i < n; i++) array[i] = next(); return array; } public char[][] nextCharMap(int n) { char[][] array = new char[n][]; for (int i = 0; i < n; i++) array[i] = next().toCharArray(); return array; } public int[][] nextIntMap(int n, int m) { int[][] map = new int[n][]; for (int i = 0; i < n; i++) { map[i] = nextIntArray(m); } return map; } } }