#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;   }