#include <bits/stdc++.h>
using namespace std;
struct SCC {
  int n;
  vector<int> comp, order;
  vector<bool> used;
  vector<vector<int> > G, RG;
  SCC(int _n = 0) : n(_n), comp(_n, -1), used(_n, false), G(_n), RG(_n) {}
  void add_edge(int from, int to) {
    G[from].push_back(to);
    RG[to].push_back(from);
  }
  void copy(const vector<vector<int> >& H) {
    for (int i = 0; i < H.size(); i++) {
      for (int j = 0; j < H[i].size(); j++) {
        G[i].push_back(H[i][j]);
        RG[H[i][j]].push_back(i);
      }
    }
  }
  int operator[](int u) const { return comp[u]; }
  void dfs(int u) {
    used[u] = true;
    for (int i = 0; i < G[u].size(); i++)
      if (!used[G[u][i]]) dfs(G[u][i]);
    order.push_back(u);
  }
  void rdfs(int u, int cnt) {
    comp[u] = cnt;
    for (int i = 0; i < RG[u].size(); i++)
      if (comp[RG[u][i]] == -1) rdfs(RG[u][i], cnt);
  }
  int build() {
    for (int i = 0; i < n; i++)
      if (!used[i]) dfs(i);
    int cnt = 0;
    for (int i = n - 1; i >= 0; i--)
      if (comp[order[i]] == -1) rdfs(order[i], cnt++);
    return cnt;
  }
  int build(vector<vector<int> >& H) {
    int ret = build();
    H.assign(ret, vector<int>());
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < G[i].size(); j++) {
        if (comp[i] != comp[G[i][j]]) H[comp[i]].push_back(comp[G[i][j]]);
      }
    }
    return ret;
  }
};
int N, M, D, K;
vector<int> G[1 << 17];
long long S[1 << 17];
SCC P;
vector<int> vs[1 << 17];
long long dist[1 << 17];
int add[1 << 17][50], cnt[1 << 17][50];
int main() {
  scanf("%d%d%d", &N, &M, &D);
  P = SCC(N);
  for (int i = 0; i < M; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    u--, v--;
    G[u].push_back(v);
    P.add_edge(u, v);
  }
  for (int i = 0; i < N; i++) {
    scanf("\n");
    for (int j = 0; j < D; j++) {
      char c;
      scanf("%c", &c);
      if (c == '1') S[i] |= 1LL << j;
    }
  }
  int K = P.build();
  for (int i = 0; i < N; i++) vs[P[i]].push_back(i);
  const long long msk = (1LL << D) - 1;
  for (int k = K; k--;) {
    dist[vs[k][0]] = 1;
    queue<int> Q;
    Q.push(vs[k][0]);
    while (!Q.empty()) {
      int u = Q.front();
      Q.pop();
      for (int v : G[u]) {
        if (k == P[v]) {
          long long nxt = dist[u] << 1 & msk | dist[u] >> D - 1;
          if (nxt & ~dist[v]) {
            dist[v] |= nxt;
            Q.push(v);
          }
        }
      }
    }
    for (int u : vs[k])
      for (int v : G[u])
        if (k != P[v]) {
          vector<int> ret(D);
          for (int d2 = 0; d2 < D; d2++) {
            int nd = (d2 + 1) % D;
            for (int d3 = 0; d3 < D; d3++)
              if (dist[v] >> d3 & 1) {
                int d4 = (nd - d3 + D) % D;
                ret[d2] = max(ret[d2], cnt[P[v]][d4] + add[P[v]][d4]);
              }
          }
          for (int d = 0; d < D; d++) {
            for (int d2 = 0; d2 < D; d2++)
              if (dist[u] >> d2 & 1) {
                add[k][d] = max(add[k][d], ret[(d + d2) % D]);
              }
          }
        }
    for (int d = 0; d < D; d++) {
      for (int u : vs[k]) {
        long long now = dist[u];
        if (now & S[u]) cnt[k][d]++;
        dist[u] = dist[u] << 1 & msk | dist[u] >> D - 1;
      }
    }
  }
  printf("%d\n", add[P[0]][0] + cnt[P[0]][0]);
}
