Problem J
Triple-Free Binary Strings
Input: Standard Input
Output: Standard Output
A binary string consists of ones and zeros. Given a binary string T, if there is no binary string S such that SSS (concatenate three copies of S together) is a substring of T, we say T is triple-free.
A pattern consists of ones, zeros and asterisks, where an asterisk(*) can be replaced by either one or zero. For example, the pattern 0**1 contains strings 0001, 0011, 0101, 0111, but not 1001 or 0000.
Given a pattern P, how many triple-free binary strings does it contain?
Input
Each line of the input represents a test case, which contains the length of pattern, n(0<n<31), and the pattern P. There can be maximum 35 test cases.
The input terminates when n=0.
Output
For each test case, print the case number and the answer, shown below.
Sample Input Output for Sample Input
4 0**1 5 ***** 10 **01**01** 0 | Case 1: 2 Case 2: 16 Case 3: 9 |
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Queue;
import java.util.LinkedList;
class Main
{
public static final boolean DEBUG = false;
public static final int MaxNodes = 36000;
public static final int N = 2, M = 40;
public static int[][] ch = new int[MaxNodes][N];
public static int[] flag = new int[MaxNodes];
public static int[] fail = new int[MaxNodes];
public static int[][] f = new int[M][MaxNodes];
public static int numOfNodes;
public static void insert(int w, int len)
{
int cur = 0;
for (int i = 0; i < len; i++) {
int c = (w >> i) & 1;
if (ch[cur][c] == 0) {
ch[cur][c] = numOfNodes++;
}
cur = ch[cur][c];
}
flag[cur] = 1;
}
public static void getFail()
{
Queue<Integer> q = new LinkedList<Integer>();
q.add(0);
while (!q.isEmpty()) {
int u = q.poll();
for (int i = 0; i < N; i++) {
int v = ch[u][i];
if (v == 0) continue;
if (u == 0) {
fail[v] = 0;
} else {
int f = fail[u];
while (f != 0 && ch[f][i] == 0) f = fail[f];
fail[v] = ch[f][i];
}
flag[v] |= flag[u] | flag[fail[v]];
q.add(v);
}
}
}
public static int next(int u, int c)
{
while (u != 0 && ch[u][c] == 0) u = fail[u];
return ch[u][c];
}
public static void init()
{
numOfNodes = 1;
for (int i = 1; i <= 10; i++) {
for (int j = 0; j < (1 << i); j++) {
insert(j | (j << i) | (j << (2 * i)), 3 * i);
}
}
getFail();
}
public static void main(String[] args) throws IOException
{
Scanner cin;
int n;
int cs = 1;
if (DEBUG) {
cin = new Scanner(new FileReader("d:\\OJ\\uva_in.txt"));
} else {
cin = new Scanner(new InputStreamReader(System.in));
}
init();
while (cin.hasNext()) {
n = cin.nextInt();
if (n == 0) break;
String s = cin.next();
char[] pat = s.toCharArray();
for (int i = 0; i < numOfNodes; i++) {
f[n][i] = (flag[i] == 1) ? 0 : 1;
}
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < numOfNodes; j++) {
if (flag[j] != 0) continue;
f[i][j] = 0;
for (int k = 0; k < N; k++) {
if (pat[i] != '*' && pat[i] != '0' + k) continue;
f[i][j] += f[i + 1][next(j, k)];
}
}
}
System.out.println("Case " + (cs++) + ": " + f[0][0]);
}
}
}