Problem:
Score : 400 points

Problem Statement

Consider a grid with H rows and W columns of squares. Let (r, c) denote the square at the r-th row from the top and the c-th column from the left.
Each square is painted black or white.

The grid is said to be good if and only if the following condition is satisfied:

From (1, 1), we can reach (H, W) by moving one square right or down repeatedly, while always being on a white square.

Note that (1, 1) and (H, W) must be white if the grid is good.

Your task is to make the grid good by repeating the operation below. Find the minimum number of operations needed to complete the task. It can be proved that you can always complete the task in a finite number of operations.

Choose four integers r_0, c_0, r_1, c_1(1 \leq r_0 \leq r_1 \leq H, 1 \leq c_0 \leq c_1 \leq W). For each pair r, c (r_0 \leq r \leq r_1, c_0 \leq c \leq c_1), invert the color of (r, c) - that is, from white to black and vice versa.

Constraints

2 \leq H, W \leq 100

Input

Input is given from Standard Input in the following format:

H W
s_{11} s_{12} \cdots s_{1W}
s_{21} s_{22} \cdots s_{2W}
\vdots
s_{H1} s_{H2} \cdots s_{HW}

Here s_{rc} represents the color of (r, c) - # stands for black, and . stands for white.

Output

Print the minimum number of operations needed.

Sample Input 1

3 3
.##
.#.
##.

Sample Output 1

1

Do the operation with (r_0, c_0, r_1, c_1) = (2, 2, 2, 2) to change just the color of (2, 2), and we are done.

Sample Input 2

2 2
#.
.#

Sample Output 2

2

Sample Input 3

4 4
..##
#...
###.
###.

Sample Output 3

0

No operation may be needed.

Sample Input 4

5 5
.#.#.
#.#.#
.#.#.
#.#.#
.#.#.

Sample Output 4

4

Solution in Rust (1.15.1) (judge verdict: Accepted)

// The main code is at the very bottom.

#[allow(unused_imports)]
#[macro_use]
pub mod spella {
  pub mod byte {
    pub use self::byte_char::*;
    pub use self::byte_str::*;
    pub use self::byte_string::*;
    pub use self::from_byte_str::*;

    mod byte_char {
      use std::fmt::{self, Debug, Display, Formatter};

      #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteChar(pub u8);

      impl Debug for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "b'{}'", self.0 as char)
        }
      }

      impl Display for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "{}", self.0 as char)
        }
      }
    }

    mod byte_str {
      use spella::byte::{ByteChar, ByteString};
      use std::fmt::{self, Debug, Display, Formatter};
      use std::ops::{Deref, DerefMut};

      #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteStr([ByteChar]);

      macro_rules! cast {
        (mut $x:expr, $($T:ty)=>*) => {
          unsafe { &mut *($x $(as *mut $T)*) }
        };
        ($x:expr, $($T:ty)=>*) => {
          unsafe { &*($x $(as *const $T)*) }
        };
      }

      impl ByteStr {
        pub fn from_bytes(s: &[u8]) -> &Self {
          cast!(s, [u8] => [ByteChar] => ByteStr)
        }

        pub fn from_bytes_mut(s: &mut [u8]) -> &mut Self {
          cast!(mut s, [u8] => [ByteChar] => ByteStr)
        }

        pub fn from_byte_chars(s: &[ByteChar]) -> &Self {
          cast!(s, [ByteChar] => ByteStr)
        }

        pub fn from_byte_chars_mut(s: &mut [ByteChar]) -> &mut Self {
          cast!(mut s, [ByteChar] => ByteStr)
        }

        pub fn as_byte_chars(&self) -> &[ByteChar] {
          &self.0
        }

        pub fn as_byte_chars_mut(&mut self) -> &mut [ByteChar] {
          &mut self.0
        }

        pub fn as_bytes(&self) -> &[u8] {
          cast!(self, ByteStr => [ByteChar] => [u8])
        }

        pub fn as_bytes_mut(&mut self) -> &mut [u8] {
          cast!(mut self, ByteStr => [ByteChar] => [u8])
        }
      }

      impl ToOwned for ByteStr {
        type Owned = ByteString;

        fn to_owned(&self) -> ByteString {
          ByteString::from(self.0.to_owned())
        }
      }

      impl Debug for ByteStr {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "b\"")?;

          for &c in &self.0 {
            write!(f, "{}", c)?;
          }

          write!(f, "\"")
        }
      }

      impl Display for ByteStr {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          for &c in &self.0 {
            write!(f, "{}", c)?;
          }

          Ok(())
        }
      }

      impl Deref for ByteStr {
        type Target = [ByteChar];

        fn deref(&self) -> &[ByteChar] {
          self.as_byte_chars()
        }
      }

      impl DerefMut for ByteStr {
        fn deref_mut(&mut self) -> &mut [ByteChar] {
          self.as_byte_chars_mut()
        }
      }
    }

    mod byte_string {
      use spella::byte::{ByteChar, ByteStr};

      use std::borrow::{Borrow, BorrowMut};
      use std::fmt::{self, Debug, Display, Formatter};
      use std::ops::{Deref, DerefMut};

      #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteString(Vec<ByteChar>);

      impl ByteString {
        pub fn into_byte_chars(self) -> Vec<ByteChar> {
          self.0
        }

        pub fn as_byte_str(&self) -> &ByteStr {
          ByteStr::from_byte_chars(&self.0)
        }

        pub fn as_mut_byte_str(&mut self) -> &mut ByteStr {
          ByteStr::from_byte_chars_mut(&mut self.0)
        }
      }

      impl From<Vec<ByteChar>> for ByteString {
        fn from(s: Vec<ByteChar>) -> ByteString {
          ByteString(s)
        }
      }

      impl Borrow<ByteStr> for ByteString {
        fn borrow(&self) -> &ByteStr {
          self.as_byte_str()
        }
      }

      impl BorrowMut<ByteStr> for ByteString {
        fn borrow_mut(&mut self) -> &mut ByteStr {
          self.as_mut_byte_str()
        }
      }

      impl Debug for ByteString {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          Debug::fmt(self.as_byte_str(), f)
        }
      }

      impl Display for ByteString {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          Display::fmt(self.as_byte_str(), f)
        }
      }

      impl Deref for ByteString {
        type Target = ByteStr;

        fn deref(&self) -> &ByteStr {
          ByteStr::from_byte_chars(&self.0)
        }
      }

      impl DerefMut for ByteString {
        fn deref_mut(&mut self) -> &mut ByteStr {
          ByteStr::from_byte_chars_mut(&mut self.0)
        }
      }
    }

    mod from_byte_str {
      use spella::byte::{ByteChar, ByteStr, ByteString};

      use std::error::Error;
      use std::fmt::{self, Debug, Display, Formatter};
      use std::str::{self, FromStr, Utf8Error};

      pub trait FromByteStr: Sized {
        type Err;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err>;
      }

      macro_rules! fn_description {
        () => {
          fn description(&self) -> &str {
            "description() is deprecated; use Display"
          }
        };
      }

      #[derive(Debug)]
      pub struct ParseByteCharError(ParseByteCharErrorKind);

      #[derive(Debug)]
      enum ParseByteCharErrorKind {
        EmptyByteStr,
        TooManyByteChars,
      }

      impl Display for ParseByteCharError {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseByteCharErrorKind::*;

          f.write_str(match self.0 {
            EmptyByteStr => "empty `ByteStr`",
            TooManyByteChars => "too many `ByteChar`s",
          })
        }
      }

      impl Error for ParseByteCharError {
        fn_description! {}
      }

      impl FromByteStr for ByteChar {
        type Err = ParseByteCharError;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err> {
          use self::ParseByteCharErrorKind::*;

          match s.len() {
            1 => Ok(unsafe { *s.get_unchecked(0) }),
            0 => Err(ParseByteCharError(EmptyByteStr)),
            _ => Err(ParseByteCharError(TooManyByteChars)),
          }
        }
      }

      #[derive(Debug)]
      pub enum ParseByteStringError {}

      impl Display for ParseByteStringError {
        fn fmt(&self, _: &mut Formatter) -> fmt::Result {
          match *self {}
        }
      }

      impl Error for ParseByteStringError {
        fn_description! {}
      }

      impl FromByteStr for ByteString {
        type Err = ParseByteStringError;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err> {
          Ok(ByteString::from(s.to_vec()))
        }
      }

      pub struct ParseFromStrError<T: FromStr>(ParseFromStrErrorKind<T>);

      enum ParseFromStrErrorKind<T: FromStr> {
        Utf8Error(Utf8Error),
        FromStrError(T::Err),
      }

      impl<T: FromStr> Debug for ParseFromStrError<T>
      where
        T::Err: Debug,
      {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseFromStrErrorKind::*;

          match self.0 {
            Utf8Error(ref err) => f.debug_tuple("Utf8Error").field(err).finish(),
            FromStrError(ref err) => f.debug_tuple("FromStrError").field(err).finish(),
          }
        }
      }

      impl<T: FromStr> Display for ParseFromStrError<T>
      where
        T::Err: Display,
      {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseFromStrErrorKind::*;

          match self.0 {
            Utf8Error(ref err) => write!(f, "{}", err),
            FromStrError(ref err) => write!(f, "{}", err),
          }
        }
      }

      impl<T: FromStr> Error for ParseFromStrError<T>
      where
        T::Err: Debug + Display,
      {
        fn_description! {}
      }

      impl<T: FromStr> FromByteStr for T {
        type Err = ParseFromStrError<T>;

        fn from_byte_str(s: &ByteStr) -> Result<T, Self::Err> {
          use self::ParseFromStrErrorKind::*;

          str::from_utf8(s.as_bytes())
            .map_err(|e| ParseFromStrError(Utf8Error(e)))
            .and_then(|s| s.parse().map_err(|e| ParseFromStrError(FromStrError(e))))
        }
      }
    }
  }

  pub mod io {
    pub use self::scanner::*;

    mod scanner {
      use spella::byte::{ByteStr, FromByteStr};

      use std::io::{self, BufRead};

      #[derive(Debug)]
      pub struct Scanner<R> {
        reader: R,
        buf: Vec<u8>,
        pos: usize,
      }

      const INITIAL_CAPACITY: usize = 32;

      impl<R: BufRead> Scanner<R> {
        pub fn new(reader: R) -> Self {
          Scanner {
            reader: reader,
            buf: Vec::with_capacity(INITIAL_CAPACITY),
            pos: 0,
          }
        }

        pub fn next<T: FromByteStr>(&mut self) -> io::Result<Result<T, T::Err>> {
          self.next_byte_str().map(T::from_byte_str)
        }

        pub fn next_byte_str(&mut self) -> io::Result<&ByteStr> {
          if self.buf.is_empty() {
            self.read_line()?;
          }

          loop {
            match self.buf.get(self.pos) {
              Some(&b' ') => self.pos += 1,
              Some(&b'\n') => self.read_line()?,
              Some(_) => break,
              None => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
            }
          }

          let start = self.pos;
          self.pos += 1;

          loop {
            match self.buf.get(self.pos) {
              Some(&b' ') | Some(&b'\n') | None => break,
              Some(_) => self.pos += 1,
            }
          }

          Ok(ByteStr::from_bytes(&self.buf[start..self.pos]))
        }

        fn read_line(&mut self) -> io::Result<()> {
          self.buf.clear();
          self.pos = 0;
          self.reader.read_until(b'\n', &mut self.buf)?;

          Ok(())
        }
      }
    }
  }
}

pub mod stopgap {
  use std::fmt::{self, Debug, Display, Formatter};
  use std::hash::{Hash, Hasher};
  use std::iter::{Product, Sum};
  use std::marker::PhantomData;
  use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

  pub trait Constant<T> {
    fn get() -> T;
  }

  pub enum _1000000007 {}

  impl Constant<u32> for _1000000007 {
    fn get() -> u32 {
      1000000007
    }
  }

  pub struct ModU32<Mod> {
    _phantom: PhantomData<fn() -> Mod>,
    repr: u32,
  }

  impl<Mod: Constant<u32>> Clone for ModU32<Mod> {
    fn clone(&self) -> Self {
      Self::from_repr(self.repr)
    }
  }

  impl<Mod: Constant<u32>> Copy for ModU32<Mod> {}

  impl<Mod: Constant<u32>> PartialEq for ModU32<Mod> {
    fn eq(&self, other: &Self) -> bool {
      self.repr.eq(&other.repr)
    }
  }

  impl<Mod: Constant<u32>> Eq for ModU32<Mod> {}

  impl<Mod: Constant<u32>> Default for ModU32<Mod> {
    fn default() -> Self {
      ModU32::from_repr(u32::default())
    }
  }

  impl<Mod: Constant<u32>> Hash for ModU32<Mod> {
    fn hash<H>(&self, state: &mut H)
    where
      H: Hasher,
    {
      self.repr.hash(state);
    }
  }

  impl<Mod: Constant<u32>> Debug for ModU32<Mod> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
      Debug::fmt(&self.repr, f)
    }
  }

  impl<Mod: Constant<u32>> Display for ModU32<Mod> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
      Display::fmt(&self.repr, f)
    }
  }

  impl<Mod: Constant<u32>> ModU32<Mod> {
    pub fn new(value: u32) -> Self {
      Self::from_repr(value % Mod::get())
    }

    fn from_repr(repr: u32) -> Self {
      debug_assert!(repr < Mod::get());
      ModU32 {
        _phantom: PhantomData,
        repr: repr,
      }
    }

    pub fn repr(self) -> u32 {
      self.repr
    }

    pub fn inverse(self) -> Self {
      let mut a = self.repr as i64;
      let mut b = Mod::get() as i64;
      let mut u = 1i64;
      let mut v = 0i64;
      while b != 0 {
        let t = a / b;
        a -= t * b;
        ::std::mem::swap(&mut a, &mut b);
        u -= t * v;
        ::std::mem::swap(&mut u, &mut v);
      }
      u %= Mod::get() as i64;
      if u < 0 {
        u += Mod::get() as i64;
      }
      Self::from_repr(u as u32)
    }

    pub fn pow(mut self, mut n: u32) -> Self {
      let mut acc = ModU32::from_repr(1);
      while n > 0 {
        if n % 2 == 1 {
          acc *= self;
        }
        self *= self;
        n /= 2;
      }
      acc
    }
  }

  impl<Mod: Constant<u32>> Add for ModU32<Mod> {
    type Output = Self;

    fn add(mut self, rhs: Self) -> Self {
      self += rhs;
      self
    }
  }

  impl<Mod: Constant<u32>> AddAssign for ModU32<Mod> {
    fn add_assign(&mut self, rhs: Self) {
      self.repr += rhs.repr;
      if self.repr >= Mod::get() {
        self.repr -= Mod::get();
      }
    }
  }

  impl<Mod: Constant<u32>> Sub for ModU32<Mod> {
    type Output = Self;

    fn sub(mut self, rhs: Self) -> Self {
      self -= rhs;
      self
    }
  }

  impl<Mod: Constant<u32>> SubAssign for ModU32<Mod> {
    fn sub_assign(&mut self, rhs: Self) {
      if self.repr < rhs.repr {
        self.repr += Mod::get();
      }
      self.repr -= rhs.repr;
    }
  }

  impl<Mod: Constant<u32>> Mul for ModU32<Mod> {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
      Self::from_repr((self.repr as u64 * rhs.repr as u64 % Mod::get() as u64) as u32)
    }
  }

  impl<Mod: Constant<u32>> MulAssign for ModU32<Mod> {
    fn mul_assign(&mut self, rhs: Self) {
      *self = *self * rhs;
    }
  }

  impl<Mod: Constant<u32>> Div for ModU32<Mod> {
    type Output = Self;

    fn div(self, rhs: Self) -> Self {
      self * rhs.inverse()
    }
  }

  impl<Mod: Constant<u32>> DivAssign for ModU32<Mod> {
    fn div_assign(&mut self, rhs: Self) {
      *self *= rhs.inverse();
    }
  }

  impl<Mod: Constant<u32>> Sum for ModU32<Mod> {
    fn sum<I>(iter: I) -> Self
    where
      I: Iterator<Item = Self>,
    {
      let mut acc = ModU32::from_repr(0);
      for x in iter {
        acc += x;
      }
      acc
    }
  }

  impl<Mod: Constant<u32>> Product for ModU32<Mod> {
    fn product<I>(iter: I) -> Self
    where
      I: Iterator<Item = Self>,
    {
      let mut acc = ModU32::from_repr(1);
      for x in iter {
        acc *= x;
      }
      acc
    }
  }

  pub fn mod_pow<Mod: Constant<u32>>(base: u32, n: u32) -> ModU32<Mod> {
    ModU32::new(base).pow(n)
  }

  pub fn mod_binomial<Mod: Constant<u32>>(mut n: u32, mut k: u32) -> ModU32<Mod> {
    let mut acc = ModU32::from_repr(1);
    while k != 0 {
      {
        let n = n % Mod::get();
        let k = k % Mod::get();
        if n < k {
          return ModU32::from_repr(0);
        }
        acc *= (n - k + 1..n + 1).map(ModU32::from_repr).product();
        acc /= (1..k + 1).map(ModU32::from_repr).product();
      }
      n /= Mod::get();
      k /= Mod::get();
    }
    acc
  }
}

#[allow(unused_imports)]
use stopgap::*;

mod prelude {
  pub use spella::byte::{ByteChar, ByteStr, ByteString};
  pub use std::collections::*;
  pub use std::io::prelude::*;
  pub use std::iter::FromIterator;
  pub use std::marker::PhantomData;
  pub use std::num::Wrapping;
  pub use std::ops::{Range, RangeFrom, RangeTo};
  pub use std::{cell, cmp, f64, i32, i64, isize, iter, mem, rc, str, time, u32, u64, usize};
}

use prelude::*;

const CUSTOM_STACK_SIZE_MEBIBYTES: Option<usize> = None;

fn main() {
  fn exec_solver() {
    let stdin = std::io::stdin();
    let stdout = std::io::stdout();
    #[cfg(not(debug_assertions))]
    let mut writer = std::io::BufWriter::new(stdout.lock());
    #[cfg(debug_assertions)]
    let mut writer = stdout.lock();
    solve(stdin.lock(), &mut writer);
    writer.flush().unwrap();
  }

  if let Some(stack_size_mebibytes) = CUSTOM_STACK_SIZE_MEBIBYTES {
    std::thread::Builder::new()
      .name("exec_solver".to_owned())
      .stack_size(stack_size_mebibytes * 1024 * 1024)
      .spawn(exec_solver)
      .unwrap()
      .join()
      .unwrap();
  } else {
    exec_solver();
  }
}

fn solve<R: BufRead, W: Write>(reader: R, mut writer: W) {
  let mut _scanner = spella::io::Scanner::new(reader);

  #[allow(unused_macros)]
  macro_rules! scan {
    ($T:ty) => {
      _scanner.next::<$T>().unwrap().unwrap()
    };
    ($($T:ty),+) => {
      ($(scan!($T)),+)
    };
    ($($T:ty),+; $n:expr $(; $m:expr)*) => {{
      (0..$n).map(|_| scan!($($T),+ $(; $m)*)).collect::<Vec<_>>()
    }};
  }

  #[allow(unused_macros)]
  macro_rules! scan_iter {
    ($($T:ty),+; $n:expr) => {
      (0..$n).map(|_| scan!($($T),+))
    };
  }

  #[allow(unused_macros)]
  macro_rules! print {
    ($fmt:expr) => {
      write!(writer, $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      write!(writer, $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! println {
    ($fmt:expr) => {
      writeln!(writer, $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      writeln!(writer, $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! eprint {
    ($fmt:expr) => {
      #[cfg(debug_assertions)]
      write!(std::io::stderr(), $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      #[cfg(debug_assertions)]
      write!(std::io::stderr(), $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! eprintln {
    ($fmt:expr) => {
      #[cfg(debug_assertions)]
      writeln!(std::io::stderr(), $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      #[cfg(debug_assertions)]
      writeln!(std::io::stderr(), $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! dbg {
    ($($x:expr),+) => {{
      eprintln!(concat!("[{}:{}] ", $(stringify!($x), " = {:?}; "),+), file!(), line!(), $($x),+);
    }};
  }

  let (h, w) = scan!(usize, usize);

  let s = scan_iter!(ByteString; h)
    .map(|s_i| s_i.into_iter().map(|b| b.0 == b'#').collect::<Vec<_>>())
    .collect::<Vec<_>>();

  fn dp(
    memo: &mut Vec<Vec<Option<u64>>>,
    s: &Vec<Vec<bool>>,
    h: usize,
    w: usize,
    i: usize,
    j: usize,
  ) -> u64 {
    if let Some(ans) = memo[i][j] {
      return ans;
    }
    let ans = if i == h - 1 && j == w - 1 {
      0
    } else {
      let mut min = u64::MAX;
      if i + 1 < h {
        min = cmp::min(
          min,
          match (s[i][j], s[i + 1][j]) {
            (false, false) => dp(memo, s, h, w, i + 1, j),
            (false, true) => 1 + dp(memo, s, h, w, i + 1, j),
            (true, false) => dp(memo, s, h, w, i + 1, j),
            (true, true) => dp(memo, s, h, w, i + 1, j),
          },
        );
      }
      if j + 1 < w {
        min = cmp::min(
          min,
          match (s[i][j], s[i][j + 1]) {
            (false, false) => dp(memo, s, h, w, i, j + 1),
            (false, true) => 1 + dp(memo, s, h, w, i, j + 1),
            (true, false) => dp(memo, s, h, w, i, j + 1),
            (true, true) => dp(memo, s, h, w, i, j + 1),
          },
        );
      }
      min
    };
    memo[i][j] = Some(ans);
    dbg!(i, j, ans);
    ans
  }

  let ans = s[0][0] as u64 + dp(&mut vec![vec![None; w]; h], &s, h, w, 0, 0);
  println!("{}", ans);
}