Problem:
Score : 1600 points

Problem Statement

Taichi thinks a binary string X of odd length N is beautiful if it is possible to apply the following operation \frac{N-1}{2} times so that the only character of the resulting string is 1 :

Choose three consecutive bits of X and replace them by their median. For example, we can turn 00110 into 010 by applying the operation to the middle three bits.

Taichi has a string S consisting of characters 0, 1 and ?. Taichi wants to know the number of ways to replace the question marks with 1 or 0 so that the resulting string is beautiful, modulo 10^{9} + 7.

Constraints

1 \leq |S| \leq 300000

|S| is odd.

All characters of S are either 0, 1 or ?.

Input

Input is given from Standard Input in the following format:

S

Output

Print the number of ways to replace the question marks so that the resulting string is beautiful, modulo 10^{9} + 7.

Sample Input 1

1??00

Sample Output 1

2

There are 4 ways to replace the question marks with 0 or 1 :

11100 : This string is beautiful because we can first perform the operation on the last 3 bits to get 110 and then on the only 3 bits to get 1.

11000 : This string is beautiful because we can first perform the operation on the last 3 bits to get 110 and then on the only 3 bits to get 1.

10100 : This string is not beautiful because there is no sequence of operations such that the final string is 1.

10000 : This string is not beautiful because there is no sequence of operations such that the final string is 1.

Thus, there are 2 ways to form a beautiful string.

Sample Input 2

?

Sample Output 2

1

In this case, 1 is the only beautiful string.

Sample Input 3

?0101???10???00?1???????????????0????????????1????0

Sample Output 3

402589311

Remember to output your answer modulo 10^{9} + 7.

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author ngfam
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		OutputWriter out = new OutputWriter(outputStream);
		EMedianReplace solver = new EMedianReplace();
		solver.solve(1, in, out);
		out.close();
	}

	static class EMedianReplace {
		static int MOD = 1000000007;

		public void solve(int testNumber, InputReader in, OutputWriter out) {
			String s = in.nextString();
			int n = s.length();

			int[] suf = new int[n + 1];
			for (int i = n - 1; i >= 0; --i) {
				suf[i] = suf[i + 1];
				if (s.charAt(i) == '?') suf[i]++;
			}

			int[] pw2 = new int[n + 1];

			pw2[0] = 1;
			for (int i = 1; i <= n; ++i) {
				pw2[i] = (pw2[i - 1] * 2) % MOD;
			}

			long ans = 0;
			long[][][][] dp = new long[n + 1][3][3][3];

			dp[0][0][0][0] = 1;
			for (int i = 0; i < n; ++i) {
				/// first take out all the countone = 2 shit
				for (int countZero = 0; countZero < 3; ++countZero) {
					for (int countOne = 0; countOne < 3; ++countOne) {
						ans += dp[i][2][countZero][countOne] * pw2[suf[i]] % MOD;
						ans %= MOD;
						dp[i][2][countZero][countOne] = 0;
					}
				}
				for (int prefix = 0; prefix < 2; ++prefix) {
					for (int countZero = 0; countZero < 3; ++countZero) {
						for (int countOne = 0; countOne + countZero < 3; ++countOne) {
							if (dp[i][prefix][countZero][countOne] == 0) continue;


							if (s.charAt(i) == '1' || s.charAt(i) == '?') {
								int newprefix = prefix;
								int newCountZero = countZero;
								int newCountOne = countOne + 1;
								if (newCountOne + newCountZero == 3) {
									newCountOne--;
									newCountZero--;
								}
								if (newCountOne == 1 && newCountZero == 0) {
									newprefix++;
									newCountOne = 0;
									newCountZero = 0;


								}

								dp[i + 1][newprefix][newCountZero][newCountOne] += dp[i][prefix][countZero][countOne];
								dp[i + 1][newprefix][newCountZero][newCountOne] %= MOD;
							}
							if (s.charAt(i) == '0' || s.charAt(i) == '?') {
								int newCountZero = countZero + 1;
								int newCountOne = countOne;
								if (newCountOne + newCountZero == 3) {
									if (newCountZero == 3) {
										newCountZero = 1;
									} else {
										newCountOne--;
										newCountZero--;
									}
								}
								dp[i + 1][prefix][newCountZero][newCountOne] += dp[i][prefix][countZero][countOne];
								dp[i + 1][prefix][newCountZero][newCountOne] %= MOD;
							}
						}
					}
				}
			}


			ans += dp[n][1][0][0];
			ans %= MOD;

			ans += dp[n][1][1][1];
			ans %= MOD;

			out.println(ans);
		}

	}

	static class OutputWriter {
		private final PrintWriter writer;

		public OutputWriter(OutputStream outputStream) {
			writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
		}

		public OutputWriter(Writer writer) {
			this.writer = new PrintWriter(writer);
		}

		public void close() {
			writer.close();
		}

		public void println(long i) {
			writer.println(i);
		}

	}

	static class InputReader {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;
		private InputReader.SpaceCharFilter filter;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		public int read() {
			if (numChars == -1) {
				throw new InputMismatchException();
			}
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public String nextString() {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			StringBuilder res = new StringBuilder();
			do {
				if (Character.isValidCodePoint(c)) {
					res.appendCodePoint(c);
				}
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public boolean isSpaceChar(int c) {
			if (filter != null) {
				return filter.isSpaceChar(c);
			}
			return isWhitespace(c);
		}

		public static boolean isWhitespace(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		public interface SpaceCharFilter {
			public boolean isSpaceChar(int ch);

		}

	}
}