Problem:
Score : 1900 points

Problem Statement

Snuke has a grid with H rows and W columns. The square at the i-th row and j-th column contains a character S_{i,j}.

He can perform the following two kinds of operation on the grid:

Row-reverse: Reverse the order of the squares in a selected row.

Column-reverse: Reverse the order of the squares in a selected column.

For example, reversing the 2-nd row followed by reversing the 4-th column will result as follows:

By performing these operations any number of times in any order, how many placements of characters on the grid can be obtained?

Constraints

1≦H,W≦200

S_{i,j} is a lowercase English letter (a-z).

Input

The input is given from Standard Input in the following format:

H W
S_{1,1}S_{1,2}...S_{1,W}
S_{2,1}S_{2,2}...S_{2,W}
:
S_{H,1}S_{H,2}...S_{H,W}

Output

Print the number of placements of characters on the grid that can be obtained, modulo 1000000007 (=10^9+7).

Sample Input 1

2 2
cf
cf

Sample Output 1

6

The following 6 placements of characters can be obtained:

Sample Input 2

1 12
codefestival

Sample Output 2

2

Solution in Haskell (GHC 7.10.3) (judge verdict: Accepted)

{-# LANGUAGE ScopedTypeVariables #-}
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Control.DeepSeq
import Data.Array
import Data.Bits
import Data.Char
import Data.Functor.Identity
import Data.List
import Data.Maybe
import Data.Ord
import Data.Tree
import Data.Tuple
import qualified System.IO
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Sequence as Q
import qualified Data.ByteString.Char8 as B
import Data.Array.IO

theMod = 1000000007

swp m i j = do
  x <- readArray m i
  y <- readArray m j
  writeArray m i y
  writeArray m j x

rank :: Array (Z,Z) Z -> IO Z
rank mat0 = do
  let ((1,1),(imax,jmax)) = bounds mat0
  m ::  IOArray (Z,Z) Z <- thaw mat0
  let
    f :: Z -> Z -> IO Z
    f 0 _ = return 0
    f _ 0 = return 0
    f ii jj = do
      v <- sequence [readArray m (ii,j) | j<-[1..jj]]
      if all (== 0) v
      then f (ii-1) jj
      else do
        let j2 = head [j | (j,x) <- zip [1..] v, x/=0] 
        sequence_ [swp m (i,jj) (i,j2) | i<-[1..ii]]
        forM_ [1..ii-1] $ \ i -> do
          x <- readArray m (i,jj)
          when (x/=0) $ do
            forM_ [1..jj-1] $ \ j -> do
              x1 <- readArray m (i,j)
              x2 <- readArray m (ii,j)
              writeArray m (i,j) ((x1+x2)`mod`2)
        r <- f (ii-1) (jj-1)
        return $ r+1
  f imax jmax 

distinct xs = length xs == length (nub xs)

main = do
  [h,w] <- readLnList
  sList <- replicateM h getLine
  let s = listArray ((1,1),(h,w)) $ concat sList
  let h2 = (h+1)`div`2
  let w2 = (w+1)`div`2
  let orbit (i,j) = nub [(i,j), (i,w+1-j), (h+1-i,j), (h+1-i,w+1-j)]
  let counts = [f . map (s!) $ orbit (i,j) | i<-[1..h2], j<-[1..w2]]
  let asyms = array ((1,1),(h2,w2)) [((i,j), distinct . map (s!) $ orbit (i,j))  | i<-[1..h2], j<-[1..w2]]
  let
    mat = accumArray (+) 0 ((1,1),(h2+w2, h2*w2)) $
      [ ((i, (i-1)*w2+j), if asyms!(i,j) && j /= w+1-j then 1 else 0)
      | i<-[1..h2], j<-[1..w2]]
      ++
      [ ((h2+j, (i-1)*w2+j), if asyms!(i,j) && i /= h+1-i then 1 else 0)
      | i<-[1..h2], j<-[1..w2]]
  r <- rank mat
  -- print asyms
  -- print mat
  -- print r
  let ans = (2::Integer)^r * product (map fint counts :: [Integer])
  print $ ans `mod`theMod

f [a] = 1
f [a,b] = 1
f [a,b,c,d] = length $ nub
  [[a,b,c,d]
  ,[a,c,d,b]
  ,[a,d,b,c]
  ,[b,a,d,c]
  ,[b,c,a,d]
  ,[b,d,c,a]
  ,[c,a,b,d]
  ,[c,b,d,a]
  ,[c,d,a,b]
  ,[d,a,c,b]
  ,[d,b,a,c]
  ,[d,c,b,a]
  ]

type Z = Int
type Q = Rational
type R = Double
type S = String

fint :: (Integral a, Num b) => a -> b
fint = fromIntegral

getInt = fst . fromJust . B.readInt <$> B.getLine
getIntPair = (\[a,b]->(a,b)) <$> getInts
getInts = map (fst . fromJust . B.readInt) . B.words <$> B.getLine
getStr = B.unpack <$> B.getLine

yesNo :: Bool -> String
yesNo True = "Yes"
yesNo False = "No"

printList :: (Show a) => [a] -> IO ()
printList = putStrLn . unwords . map show

readLnList :: (Read a) => IO [a]
readLnList = map read . words <$> getLine


-----  Union-find
type UnionFindT v m a = StateT (M.Map v (UnionFindVal v)) m a
newtype UnionFindVal v = UnionFindVal v

runUnionFindT :: (Monad m) => UnionFindT v m a -> m a
runUnionFindT = flip evalStateT $ M.empty

runUnionFind = runIdentity . runUnionFindT

ufFresh :: (Monad m, Ord v) => v -> UnionFindT v m ()
ufFresh v = modify $ M.insert v (UnionFindVal v)

ufClass :: (Monad m, Ord v) => v -> UnionFindT v m v
ufClass v = do
  (UnionFindVal pv) <- gets (M.! v)
  if v == pv
    then return v
    else do
      c <- ufClass pv
      modify $ M.insert v (UnionFindVal c)
      return c

ufUnify v w = do
  cv <- ufClass v
  cw <- ufClass w
  modify $ M.insert cw (UnionFindVal cv)
  return $ cv /= cw