#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int D = 50;
vector<int> g[N], rg[N];
vector<int> G[N];
vector<int> topSort, topSortSCC;
bool used[N];
int comp[N];
void dfsTopSort(int v) {
  used[v] = true;
  for (int u : g[v]) {
    if (!used[u]) dfsTopSort(u);
  }
  topSort.push_back(v);
}
void dfsTopSortSCC(int v) {
  used[v] = true;
  for (int u : G[v]) {
    if (!used[u]) dfsTopSortSCC(u);
  }
  topSortSCC.push_back(v);
}
void dfsSCC(int v) {
  used[v] = true;
  for (int u : rg[v]) {
    if (!used[u]) {
      comp[u] = comp[v];
      dfsSCC(u);
    }
  }
}
int dp[N][D], calc[N][D];
int mark[N], dist[N], distR[N];
bool usedR[N];
int subG[N];
char s[N][D];
bool cycle[N][D];
int INF = 1e9;
vector<int> SCC[N];
void dfsIn(int v, int d) {
  used[v] = true;
  for (int u : g[v]) {
    if (comp[u] != comp[v]) continue;
    if (!used[u]) {
      dist[u] = dist[v] + 1;
      dfsIn(u, d);
    }
    for (int i = 0; i < d; ++i) cycle[v][(i + 1) % d] |= cycle[u][i];
  }
}
void dfsInR(int v) {
  usedR[v] = true;
  for (int u : rg[v]) {
    if (!usedR[u] && comp[u] == comp[v]) {
      distR[u] = distR[v] + 1;
      dfsInR(u);
    }
  }
}
int gcd(int a, int b) {
  while (b != 0) {
    a %= b;
    swap(a, b);
  }
  return a;
}
int main() {
  int n, m, d;
  scanf("%d%d%d", &n, &m, &d);
  while (m--) {
    static int u, v;
    scanf("%d%d", &u, &v);
    --u;
    --v;
    g[u].push_back(v);
    rg[v].push_back(u);
  }
  for (int v = 0; v < n; ++v) used[v] = false;
  for (int v = 0; v < n; ++v) {
    if (!used[v]) dfsTopSort(v);
  }
  reverse(topSort.begin(), topSort.end());
  for (int v = 0; v < n; ++v) used[v] = false;
  int sz = 0;
  for (int v : topSort) {
    if (!used[v]) {
      mark[sz] = v;
      comp[v] = sz++;
      dfsSCC(v);
    }
  }
  for (int v = 0; v < n; ++v) SCC[comp[v]].push_back(v);
  for (int v = 0; v < n; ++v) {
    for (int u : g[v])
      if (comp[u] != comp[v]) G[comp[v]].push_back(comp[u]);
  }
  for (int v = 0; v < n; ++v) used[v] = false;
  for (int c = 0; c < sz; ++c) {
    if (!used[c]) dfsTopSortSCC(c);
  }
  reverse(topSortSCC.begin(), topSortSCC.end());
  for (int v = 0; v < n; ++v) used[v] = usedR[v] = false;
  mark[comp[0]] = 0;
  for (int c : topSortSCC) {
    static int s;
    s = mark[c];
    dist[s] = distR[s] = 0;
    for (int v : SCC[c])
      for (int i = 0; i < d; ++i) cycle[v][i] = false;
    cycle[s][0] = true;
    dfsIn(s, d);
    dfsInR(s);
    static int g;
    g = d;
    for (int i = 0; i < d; ++i)
      if (cycle[s][i]) g = gcd(g, i);
    subG[c] = g;
  }
  for (int c = 0; c < sz; ++c) {
    for (int i = 0; i < d; ++i) {
      dp[c][i] = -INF;
      calc[c][i] = 0;
    }
  }
  for (int v = 0; v < n; ++v) scanf("%s", s[v]);
  for (int c = 0; c < sz; ++c) {
    for (int i = 0; i < d; ++i) {
      for (int v : SCC[c]) {
        int cur = 0;
        for (int x = 0; x < d; ++x)
          cur += ((s[v][x] == '1') && (x - dist[v] - i) % subG[c] == 0);
        calc[c][i] += cur > 0;
      }
    }
  }
  int c0 = comp[0];
  for (int i = 0; i < d; ++i)
    dp[c0][(i * subG[c0]) % d] = calc[c0][(i * subG[c0]) % d];
  for (int c : topSortSCC) {
    for (int v : SCC[c]) {
      for (int u : rg[v]) {
        if (comp[u] == comp[v]) continue;
        for (int i = 0; i < d; ++i) {
          for (int j = 0; j < d; ++j) {
            int delt = (i - distR[v] - 1 - (j + dist[u]));
            if (delt % subG[c] == 0 && delt % subG[comp[u]] == 0)
              dp[c][i] = max(dp[c][i], dp[comp[u]][j] + calc[c][i]);
          }
        }
      }
    }
    for (int i = subG[c]; i < d; ++i)
      dp[c][i] = max(dp[c][i], dp[c][i - subG[c]]);
    for (int i = d - subG[c] - 1; i >= 0; --i) dp[c][i] = dp[c][i + subG[c]];
  }
  int ans = 0;
  for (int c = 0; c < sz; ++c) {
    if ((int)G[c].size()) continue;
    for (int i = 0; i < d; ++i) ans = max(ans, dp[c][i]);
  }
  printf("%d", ans);
}
