Problem:
Problem F: UTF-8

UTF-8はマルチバイト文字を符号化する手法の一つである。

文字は計算機上ではバイト列として扱われる。英語だけであればラテンアルファベットおよび数字、記号を合わせても 1byteで表現できるが、残念ながら世界中で利用されている文字を1byteで表現することはできないため、複数のバイトを用いて文字を表す必要がある。

ここで例えば"あ"という文字に12354(0x3042)という2バイト列を割り当てたとき、そのままバイト列を並べると0x30,0x42と2文字なのか0x3042で1文字なのかが区別がつかない。

このため、マルチバイト文字符号化方式のUTF-8では始めの1バイト目で続くバイト列の長さが分かるようにすることにより、この問題を克服している。具体的なビットパターンは以下のようになる。

バイト長

ビットパターン

1

0xxxxxxx

2

110yyyyx 10xxxxxx

3

1110yyyy 10yxxxxx 10xxxxxx

4

11110yyy 10yyxxxx 10xxxxxx 10xxxxxx

ここでxは0/1の任意のビットとする。またyも0/1の任意のビットとなるがどれか一つは1である必要がある。また全ての文字は1,2,3,4バイト文字のいずれかであるとする。

ここでyのビットが少なくとも一つは1であるという制約は以下のような理由による。 例えば'/'(0x2f)をバイト列にエンコードする際に0x2fと1バイトで符号化するないしは0xc0 0xafと2バイトで符号化する方法の二つがあるが、このような曖昧性を許すとセキュリティ上の脅威のもととなる可能性があるためである。

以上の話を聞いたあなたはUTF-8がどの程度の自由度があるのかが気になった。具体的には与えられたバイト列の一部のビットが不明な時にUTF-8として可能なバイト列の組み合わせがどの程度あるかということである。

このとき可能なバイト列の組み合わせの個数を求め、1,000,000で割った余りを出力せよ。

Input

N
b1
b2
...
bN

Nはバイト列の個数, biはバイト列である。
1 ≤ N ≤ 1000 を満たしている。 biは記号{0/1/x}が8個並んでいる。xはビットが不明であることを示している。

Output

可能なバイト列の組み合わせの個数を1,000,000で割った余りを出力せよ。

Notes on Test Cases

上記入力形式で複数のデータセットが与えられます。各データセットに対して上記出力形式で出力を行うプログラムを作成して下さい。

N が 0 のとき入力の終わりを示します。

Sample Input

1
xxxxxxxx
3
11100000
10x00000
10111111
3
11100000
10000000
10111111
4
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
0

Output for Sample Input

128
1
0
778240

Solution in JAVA (judge verdict: Accepted)

import java.util.Scanner;

//UTF-8
public class Main{

	String[][] p = {{"0xxxxxxx"}, 
			{"110yyyyx", "10xxxxxx"},
			{"1110yyyy", "10yxxxxx", "10xxxxxx"},
			{"11110yyy", "10yyxxxx", "10xxxxxx", "10xxxxxx"}
	};

	void run(){
		Scanner sc = new Scanner(System.in);
		int MOD = 1000000;
		for(;;){
			int n = sc.nextInt();
			if(n==0)break;
			char[][] s = new char[n][8];
			for(int i=0;i<n;i++)s[i]=sc.next().toCharArray();
			long[][] dp = new long[n+1][4];
			dp[n][0] = 1;
			for(int i=n-1;i>=0;i--)for(int L=0;L<4;L++){
				if(n<=i+L)continue;
				boolean ok = true;
				int ys = 0, xs = 0, y1 = 0;
				for(int j=0;j<=L;j++)for(int k=0;k<8;k++){
					char ch = p[L][j].charAt(k);
					if(ch=='0'){
						if(s[i+j][k]=='1')ok = false;
					}
					if(ch=='1'){
						if(s[i+j][k]=='0')ok = false;
					}
					if(ch=='x'){
						if(s[i+j][k]=='x')xs++;
					}
					if(ch=='y'){
						if(s[i+j][k]=='1')y1++;
						if(s[i+j][k]=='x')ys++;
					}
				}
				if(ok){
					long res = (1L<<xs)%MOD;
					if(0<L){
						if(y1==0){
							res = (res*((1<<ys)-1))%MOD;
						}
						else{
							res = (res*(1<<ys))%MOD;
						}
					}
					for(int j=0;j<4;j++){
						dp[i][L] = (dp[i][L]+res*dp[i+L+1][j])%MOD;
					}
				}
				else dp[i][L] = 0;
			}
			long res = 0;
			for(int j=0;j<4;j++)res+=dp[0][j];
			System.out.println(res%MOD);
		}
	}

	public static void main(String[] args) {
		new Main().run();
	}
}