#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 100;
vector<int> v[maxn];
stack<int> s;
int low[maxn], dfn[maxn], vis[maxn], clk = 0;
int belong[maxn], tot = 0;
vector<int> Ws[maxn];
void tarjan(int x) {
  s.push(x), vis[x] = 1;
  low[x] = dfn[x] = ++clk;
  for (auto &u : v[x]) {
    if (!dfn[u]) {
      tarjan(u);
      low[x] = min(low[x], low[u]);
    } else if (vis[u])
      low[x] = min(low[x], dfn[u]);
  }
  if (low[x] == dfn[x]) {
    int u;
    tot++;
    do {
      u = s.top();
      s.pop(), vis[u] = 0;
      belong[u] = tot, Ws[tot].push_back(u);
    } while (x != u);
  }
}
int n, m, D;
vector<pair<int, int> > usedge[maxn];
int in[maxn];
pair<int, int> dp[maxn][55];
void buildnew() {
  Ws[0].push_back(0), in[belong[1]]++;
  belong[0] = 0, usedge[0].push_back({0, 1});
  for (int i = 1; i <= n; ++i) {
    for (auto &u : v[i]) {
      if (belong[i] != belong[u]) {
        usedge[belong[i]].push_back({i, u});
        in[belong[u]]++;
      }
    }
  }
}
char mp[maxn][55];
void calblock(int x, int time, int bx, int w) {
  time %= D;
  pair<int, int> &ret = dp[x][time];
  if (ret.first) return;
  ret = {1, w};
  for (auto &u : v[x]) {
    if (bx != belong[u]) continue;
    calblock(u, time + 1, bx, w);
  }
}
int val[maxn][55], ans[maxn][55];
int cal(int x, int p) {
  if (val[x][p] != -1) return val[x][p];
  val[x][p] = 0;
  for (auto &u : Ws[x]) {
    for (int i = 0; i < D; ++i) {
      int ok = (dp[u][i].first && mp[u][i] == '1' && dp[u][i].second == p);
      val[x][p] += ok;
      if (ok) break;
    }
  }
  return val[x][p];
}
int dis[maxn];
void solve(int x) {
  queue<int> q;
  for (int i = 0; i <= tot; ++i)
    if (!in[i]) q.push(i);
  while (q.size()) {
    int p = q.front();
    q.pop();
    for (auto &u : usedge[p]) {
      int bx = belong[u.second];
      for (int i = 0; i < D; ++i) {
        if (dp[u.first][i].first) {
          int tp = (i + 1) % D;
          int go = (dis[u.second] + i + 1) % D;
          calblock(u.second, (i + 1) % D, bx, go);
          tp = dp[u.second][(i + 1) % D].second;
          ans[bx][tp] =
              max(ans[bx][tp], ans[p][dp[u.first][i].second] + cal(bx, tp));
        }
      }
      in[bx]--;
      if (in[bx] == 0) q.push(bx);
    }
  }
}
void bfs(int x) {
  int p = Ws[x][0];
  queue<int> q;
  q.push(p);
  dis[p] = 0;
  while (q.size()) {
    int u = q.front();
    q.pop();
    for (auto r : v[u]) {
      if (belong[r] != x || (dis[r] != -1)) continue;
      dis[r] = dis[u] + 1;
      q.push(r);
    }
  }
}
int main() {
  scanf("%d%d%d", &n, &m, &D);
  for (int i = 1; i <= m; ++i) {
    int x, y;
    scanf("%d%d", &x, &y);
    v[x].push_back(y);
  }
  for (int i = 1; i <= n; ++i) {
    scanf("%s", mp[i]);
  }
  for (int i = 1; i <= n; ++i) {
    if (!dfn[i]) {
      tarjan(i);
    }
  }
  buildnew();
  memset(val, -1, sizeof val);
  memset(dis, -1, sizeof dis);
  for (int i = 0; i <= tot; ++i) bfs(i);
  dp[0][D - 1] = {1, D - 1};
  solve(0);
  int ret = 0;
  for (int i = 1; i <= tot; ++i) {
    for (int j = 1; j <= D; ++j) ret = max(ret, ans[i][j - 1]);
  }
  cout << ret << '\n';
  return 0;
}
