#include #define rep(i,a,b) for(int i=a;i=b;i--) #define fore(i,a) for(auto &i:a) #pragma GCC optimize ("-O3") using namespace std; void _main(); int main() { cin.tie(0); ios::sync_with_stdio(false); _main(); } //--------------------------------------------------------------------------------------------------- template struct ModInt { static const int Mod = MOD; unsigned x; ModInt() : x(0) { } ModInt(signed sig) { x = sig < 0 ? sig % MOD + MOD : sig % MOD; } ModInt(signed long long sig) { x = sig < 0 ? sig % MOD + MOD : sig % MOD; } int get() const { return (int)x; } ModInt &operator+=(ModInt that) { if ((x += that.x) >= MOD) x -= MOD; return *this; } ModInt &operator-=(ModInt that) { if ((x += MOD - that.x) >= MOD) x -= MOD; return *this; } ModInt &operator*=(ModInt that) { x = (unsigned long long)x * that.x % MOD; return *this; } ModInt &operator/=(ModInt that) { return *this *= that.inverse(); } ModInt operator+(ModInt that) const { return ModInt(*this) += that; } ModInt operator-(ModInt that) const { return ModInt(*this) -= that; } ModInt operator*(ModInt that) const { return ModInt(*this) *= that; } ModInt operator/(ModInt that) const { return ModInt(*this) /= that; } ModInt inverse() const { long long a = x, b = MOD, u = 1, v = 0; while (b) { long long t = a / b; a -= t * b; std::swap(a, b); u -= t * v; std::swap(u, v); } return ModInt(u); } bool operator==(ModInt that) const { return x == that.x; } bool operator!=(ModInt that) const { return x != that.x; } ModInt operator-() const { ModInt t; t.x = x == 0 ? 0 : Mod - x; return t; } }; template ostream& operator<<(ostream& st, const ModInt a) { st << a.get(); return st; }; template ModInt operator^(ModInt a, unsigned long long k) { ModInt r = 1; while (k) { if (k & 1) r *= a; a *= a; k >>= 1; } return r; } typedef ModInt<201712111> mint; string to_binary(int N, int digit = -1) { string s = ""; int ok = 0; rrep(i, 30, 0) { int m = 1 << i; if (N < m) { if(ok)s += "0"; }else s += "1", N -= m, ok = 1;} if (0 < digit and s.size() < digit) {int n = digit - s.size();rep(i, 0, n) s = "0" + s;} return s;} /*---------------------------------------------------------------------------------------------------             ∧_∧       ∧_∧  (´<_` )  Welcome to My Coding Space!      ( ´_ゝ`) /  ⌒i     /   \    | |     /   / ̄ ̄ ̄ ̄/  |   __(__ニつ/  _/ .| .|____      \/____/ (u ⊃ ---------------------------------------------------------------------------------------------------*/ #define INF INT_MAX/2 int H, W; string A[1010]; int B[1010][1010]; int dp[1010][1010]; mint dp2[400][1 << 18]; //--------------------------------------------------------------------------------------------------- void _main() { cin >> H >> W; rep(y, 0, H) cin >> A[y]; if (W <= H) { rep(y, 0, H) rep(x, 0, W) if (A[y][x] != '?') B[y][x] = A[y][x] - '0'; } else { rep(y, 0, H) rep(x, 0, W) if (A[y][x] != '?') B[x][y] = A[y][x] - '0'; swap(W, H); } rep(y, 0, H) rep(x, 0, W) dp[y][x] = INF; if (A[0][0] == '?') dp[0][0] = 1; else dp[0][0] = B[0][0]; rep(y, 0, H) rep(x, 0, W) { if (B[y + 1][x] == 0) dp[y + 1][x] = min(dp[y + 1][x], dp[y][x] + 1); else dp[y + 1][x] = min(dp[y + 1][x], dp[y][x] + B[y + 1][x]); if (B[y][x + 1] == 0) dp[y][x + 1] = min(dp[y][x + 1], dp[y][x] + 1); else dp[y][x + 1] = min(dp[y][x + 1], dp[y][x] + B[y][x + 1]); } int T = dp[H - 1][W - 1]; printf("%d\n", T); dp2[0][0] = 1; rep(y, 0, H) rep(x, 0, W) rep(msk, 0, 1 << W) { int id = y * W + x; int upok = 0; if (y) { if(msk & (1 << x)) upok = 1; if (B[y][x] == 0) { if (dp[y - 1][x] + 1 != dp[y][x]) upok = 0; } else { if (dp[y - 1][x] + B[y][x] != dp[y][x]) upok = 0; } } else { if(x == 0) upok = 1; } int leok = 0; if (x) { if (msk & (1 << (x - 1))) leok = 1; if (B[y][x] == 0) { if (dp[y][x - 1] + 1 != dp[y][x]) leok = 0; } else { if (dp[y][x - 1] + B[y][x] != dp[y][x]) leok = 0; } } if (upok or leok) { int nmsk = msk | (1 << x); dp2[id + 1][nmsk] += dp2[id][msk]; } if (!upok and !leok) { int nmsk = msk & (~(1 << x)); if (B[y][x] == 0) dp2[id + 1][nmsk] += dp2[id][msk] * 9; else dp2[id + 1][nmsk] += dp2[id][msk]; } else { if (B[y][x] == 0) { int nmsk = msk & (~(1 << x)); dp2[id + 1][nmsk] += dp2[id][msk] * 8; } } } //rep(y, 0, H) rep(x, 0, W) rep(msk, 0, 1 << W) if(dp2[y * W + x][msk].get()) printf("dp2[%d][%d][%s] = %d\n", y, x, to_binary(msk, W).c_str(), dp2[y * W + x][msk].get()); mint ans = 0; rep(msk, 0, 1 << W) if (msk & (1 << (W - 1))) ans += dp2[H * W][msk]; printf("%d\n", ans.get()); }