/*
ID: rchalam1
LANG: C++14
TASK:
*/
// For train.usaco.org, fill the template above.

// Competitive Coding Template

// GCC OPTIMIAZTION FLAGS
#ifdef ONLINE_JUDGE
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#endif

#include <bits/stdc++.h>

/*
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
*/
// All Includes for Competitive Coding Template

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;

using vi = std::vector<int>;
using vll = std::vector<long long>;
using vull = std::vector<unsigned long long>;

#define FOR(i, a, b) for (auto i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i, 0, a)
#define ROF(i, a, b) for (auto i = (a); i >= (b); --i)
#define R0F(i, a) ROF(i, a, 0)
#define ITR(a, x) for (auto& a: x)

#define FSRT(set) sort((set).begin(),(set).end())
#define RSRT(set) sort((set).rbegin(),(set).rend())
#define CSRT(set, function) sort((set).begin(),(set).end(), (function))
#define TRS(set) sort((set).begin(),(set).end(), greater<>())
#define REV(set) reverse((set).begin(),(set).end());

#define ALL(set) (set).begin(), (set).end()

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define ff first
#define ss second

// For stdio, call setIO() or setIO("").
void setIO(std::ifstream &readFile, std::ofstream &writeFile, const std::string &name = "", bool stdIO = false)
{
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	if(!name.empty() && !stdIO)
	{
		readFile.open(name + ".in");
		if(readFile.fail()) return;
		writeFile.open(name + ".out");
		std::cin.rdbuf(readFile.rdbuf());
		std::cout.rdbuf(writeFile.rdbuf());
	}
}

// To time program, create object Timer  to start timing, and call Timer.elapsed().
#include <chrono>

class Timer
{
	std::chrono::time_point<std::chrono::high_resolution_clock> m_beg;
public:
	Timer() : m_beg(std::chrono::high_resolution_clock::now())
	{}

	void reset()
	{ m_beg = std::chrono::high_resolution_clock::now(); }

	[[nodiscard]] long double elapsed() const
	{
		return std::chrono::duration_cast<std::chrono::duration<long double, std::ratio<1> >>(
				std::chrono::high_resolution_clock::now() - m_beg).count();
	}
};

// Defines datatype
using dt = int;
// Defines MAXN value
constexpr dt MAXN = 1e5 + 1;
// Defines Modulus
constexpr dt MOD = 1e9 + 7;
// Defines Floating Point Correction
constexpr long double EPS = 1e-9;

//*****
//START CODE BELOW
/*
template<class T>
class SegmentTree
{
	struct Node
	{
		T value, set, delta = 0;
		std::size_t low, high;
		bool validSet = false;
	};
	std::vector<Node> tree;
	const T type;

	void sum(const T &i)
	{ tree[i].value = tree[2 * i].value + tree[2 * i + 1].value; }

	void minimum(const T &i)
	{ tree[i].value = std::min(tree[2 * i].value, tree[2 * i + 1].value); }

	void maximum(const T &i)
	{ tree[i].value = std::max(tree[2 * i].value, tree[2 * i + 1].value); }

	void update(const T &i)
	{ type ? type == 1 ? minimum(i) : maximum(i) : sum(i); }

	void propogate(const T &i)
	{
		if(tree[i].validSet)
		{
			if(tree[i].low != tree[i].high)
			{
				tree[2 * i].set = tree[2 * i + 1].set = tree[i].set;
				tree[2 * i].delta = tree[2 * i + 1].delta = 0;
				tree[2 * i].validSet = tree[2 * i + 1].validSet = true;
			}
			tree[i].value = (type ? 1 : tree[i].high - tree[i].low + 1) * tree[i].set;
			tree[i].set = 0;
			tree[i].validSet = false;
		}
		if(tree[i].delta)
		{
			if(tree[i].low != tree[i].high)
			{
				tree[2 * i].delta += tree[i].delta;
				tree[2 * i + 1].delta += tree[i].delta;
			}
			tree[i].value += (type ? 1 : tree[i].high - tree[i].low + 1) * tree[i].delta;
			tree[i].delta = 0;
		}
	}

	void build(const T &i, const std::size_t &low, const std::size_t &high, const std::vector<T> &elements)
	{
		tree[i].low = low;
		tree[i].high = high;
		const std::size_t midpoint = low + (high - low) / 2;
		if(low == high)
		{
			tree[i].value = elements[midpoint];
			return;
		}
		build(2 * i, low, midpoint, elements);
		build(2 * i + 1, midpoint + 1, high, elements);
		update(i);
	}

public:
	explicit SegmentTree(const std::vector<T> &elements, const T &userType)
			: type{userType}
	{
		tree.resize(4 * elements.size());
		build(1, 0, elements.size() - 1, elements);
	}

	explicit SegmentTree(const T &size, const T &userType)
			: type{userType}
	{
		tree.resize(4 * size);
		build(1, 0, size - 1, vector<T>(size, 0));
	}

	void change(const std::size_t &low, const std::size_t &high, const T &delta, const bool &setAll = false, const T &i = 1)
	{
		propogate(i);
		if(low > tree[i].high || tree[i].low > high) return;
		if(low <= tree[i].low && tree[i].high <= high)
		{
			if(setAll)
			{
				tree[i].set = delta;
				tree[i].delta = 0;
				tree[i].validSet = true;
			}
			else tree[i].delta = delta;
			propogate(i);
			return;
		}
		change(low, high, delta, setAll, 2 * i);
		change(low, high, delta, setAll, 2 * i + 1);
		update(i);
	}

	[[nodiscard]] bool range(const std::size_t &low, const std::size_t &high, const T &value, const T &i = 1)
	{
		propogate(i);
		if(low > tree[i].high || tree[i].low > high) return false;
		if(low <= tree[i].low && tree[i].high <= high) return tree[i].value == value;
		return range(low, high, value, 2 * i) || range(low, high, value, 2 * i + 1);
	}
};

template<class T>
class HeavyLightDecomposition
{
	std::vector<T> sizes, parent, depth, heavy;
	std::vector<std::size_t> root, position;
	SegmentTree<T> *tree = nullptr;

	void dfs(const vector<vector<T>> &graph, const T i)
	{
		for(auto &neighbor : graph[i])
			if(neighbor != parent[i])
			{
				parent[neighbor] = i;
				depth[neighbor] = depth[i] + 1;
				dfs(graph, neighbor);
				if(heavy[i] == -1 || sizes[neighbor] > sizes[heavy[i]]) heavy[i] = neighbor;
				sizes[i] += sizes[neighbor];
			}
	}

	bool path(T &i, T &j, T &value)
	{
		for(; root[i] != root[j]; j = parent[root[j]])
		{
			if(depth[root[i]] > depth[root[j]]) std::swap(i, j);
			if(tree->range(position[i], position[j], value)) return true;
		}
		if(depth[i] > depth[j]) std::swap(i, j);
		return tree->range(position[i], position[j], value);
	}

public:
	explicit HeavyLightDecomposition(const std::vector<std::vector<T>> &graph)
	{
		sizes.assign(graph.size(), 1);
		parent.resize(graph.size());
		depth.resize(graph.size());
		heavy.assign(graph.size(), -1);
		root.resize(graph.size());
		position.resize(graph.size());
		parent[0] = -1;
		depth[0] = 0;
		dfs(graph, 0);
		for(std::size_t i = 0, index = -1; i < graph.size(); ++i)
			if(parent[i] == -1 || heavy[parent[i]] != i)
				for(T j = i; j != -1; j = heavy[j])
				{
					root[j] = i;
					position[j] = ++index;
				}
		tree = new SegmentTree<T>(graph.size(), 2);
	}

	void set(const T &i, const T &value)
	{ tree->change(position[i], position[i], value, true); }

	bool query(T &i, T &j, T value)
	{ return path(i, j, value); }
};

int main(int argc, char *argv[])
{
	static std::ifstream readFile;
	static std::ofstream writeFile;
	setIO(readFile, writeFile, "maxflow");
	ll n, m;
	cin >> n >> m;
	vector<ll> elements(n);
	for(auto &element : elements) cin >> element;
	vector<vector<ll>> graph(n);
	for(ll i = 0; i < n - 1; ++i)
	{
		ll x, y;
		cin >> x >> y;
		--x;
		--y;
		graph[x].pb(y);
		graph[y].pb(x);
	}
	HeavyLightDecomposition<ll> hld(graph);
	for(int i = 0; i < n; ++i) hld.set(i, elements[i]);
	while(m--)
	{
		ll a, b, c;
		cin >> a >> b >> c;
		cout << hld.query(--a, --b, c);
	}
	cout << '\n';
}
*/

ll n, m, k;
vector<vector<char>> matrix;

bool works(const ll &i, const ll &j)
{
	ll answer = 0;
	for(ll y = 0; y < n; ++y)
		for(ll x = 0; x < m; ++x)
			if(((1 << y) & i) && ((1 << x) & j))
				answer += (matrix[y][x] == '#');
	return answer == k;
}

int main()
{
	cin >> n >> m >> k;
	matrix.resize(n, vector<char>(m));
	for(auto &row : matrix) for(auto &node : row) cin >> node;
	ll answer = 0;
	for(ll i = 0; i < (1 << n); ++i)
		for(ll j = 0; j < (1 << m); ++j)
			answer += works(i, j);
	cout << answer << '\n';
}

Measured memory_bytes: 3576