Problem:
桜詩  願はくは花の下にて春死なむ
English text is not available in this practice contest.
Nathan O. Davis は集積回路コースの学生である．
Nathan は足りない単位を補充するために，日本文化に関する授業を履修している．今日の課題は詩の作成である．
Nathan は勉強不足で日本語が不得手なため，プログラムに詩を自動生成させようと考えた．手始めに彼は，日本語の単語の接続辞書を入手した．
あとは単語の接続にしたがってランダムな文章を生成するだけである．
しかしながら，ランダムに生成された全ての文字列が詩として認められるわけではない．
詩には，いくつかの季語のうち1つが，一度だけ現れていなければならない．ある季語が2回以上出現することや，2種類以上の季語が1回ずつ出現することは許されない．
また，季語は単語の接続の境界をまたいで出現してもよい．
あなたの仕事は，入力で与えられた単語の接続辞書と季語のリストから，指定された長さの詩が何通りに作られるかを求めるプログラムを作成することである．
違う単語を繋げて詩となる同じ文字列が得られた場合，それらは重複して数え上げるものとする．答えは非常に大きくなりうるので， 1,000,000,007 で割った余りを出力せよ．
Input
入力は複数のテストケースを含んでいる．1つのテストケースは，以下の形式で与えられる．
N
M
K
from
1
to
1
from
2
to
2
:
from
N
to
N
seasonword
1
seasonword
2
:
seasonword
K
入力の最初の行には3つの整数
N
(1 ≤
N
≤ 250),
M
(1 ≤
M
≤ 500),
K
(1 ≤
K
≤ 30) が含まれ，それぞれ単語の接続辞書の大きさ，作成すべき詩の長さ，季語の数を表す．
続く
N
行は単語の接続辞書の情報を表す．
各行は2つの文字列
from
i
,
to
i
を含み，単語
from
i
の後に続けて単語
to
i
が出現してもよいということを表す．
to
i
の後に続けて
from
i
が出現してもよいということを表すものではないことに注意せよ．また，
from
i
で終わるような他の文字列の後に続けて
to
i
が出現してもよいということを表すものでもない．詩は，接続辞書に含まれるどの単語から始めてもよい．

続く
K
行は1つの文字列
seasonword
i
からなり，それぞれ季語を表す．

入力中に現れる文字列は全て小文字のアルファベットからなり，その長さは 1 以上 20 以下である．

接続辞書の各項目，および季語は互いに異なる．
すなわち，
i
≠
j
に対して
from
i
≠
from
j
または
to
i
≠
to
j
が成り立つ．
同様に，
i
≠
j
に対して
seasonword
i
≠
seasonword
j
が成り立つ．

入力の末尾には，入力の終了を表す 3 つの 0 がある．
Output
生成される異なる詩の数を 1,000,000,007 で割った余りを1行に出力せよ．
先に言及したように，違う単語を繋げて詩となる同じ文字列が得られた場合，それらは重複して数え上げるものとする．
厳密に言えば，2つの詩
s
,
t
があり，それぞれ単語の列 [
a
1
,
a
2
, ...,
a
n
], [
b
1
,
b
2
, ...,
b
m
] を順に連結して得られたものであるとき，
n
=
m
かつすべての 1 ≤
i
≤
n
に対して
a
i
=
b
i
であるとき，またそのときに限って，2つの詩
s
,
t
は同一の詩とみなされる．
Sample Input
4 64 2
negawakuha hananoshitanite
hananoshitanite harushinan
harushinan sonokisaragino
sonokisaragino mochizukinokoro
sakura
hana
2 15 2
naha naha
naha gachoon
sakura
hana
3 7 2
asakur a
a sakura
asa kura
sakura
hana
9 100 2
a a
a h
a n
h a
h h
h n
n a
n h
n n
sakura
hana
4 2 2
a a
a b
b a
b b
ab
b
4 7 4
i cpc
mi cp
ac mi
cp c
ac
wa
tle
re
0 0 0
Output for the Sample Input
1
1
3
715991824
1
1

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define ALL(x) (x).begin(),(x).end()

using namespace std;

using ll = long long;
using ld = long double;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

struct yes_no : numpunct<char> {
  string_type do_truename()  const { return "Yes"; }
  string_type do_falsename() const { return "No"; }
};

template<int M, bool IsPrime = false>
class Modulo {
  using ll = long long;
  int n;
  static enable_if_t<IsPrime, ll> inv(ll a, ll p) {
    return (a == 1 ? 1 : (1 - p * inv(p%a, a)) / a + p);
  }
public:
  Modulo () : n(0) {;}
  Modulo (int m) : n(m) {
    if (n >= M) n %= M;
    else if (n < 0) n = (n % M + M) % M;
  }
  Modulo (ll m) {
    if (m >= M) m %= M;
    else if (m < 0) m = (m % M + M) % M;
    n = m;
  }
  explicit operator int() const { return n; }
  explicit operator ll() const { return n; }
  bool operator==(const Modulo &a) const { return n == a.n; }
  Modulo operator+=(const Modulo &a) { n += a.n; if (n >= M) n -= M; return *this; }
  Modulo operator-=(const Modulo &a) { n -= a.n; if (n < 0) n += M; return *this; }
  Modulo operator*=(const Modulo &a) { n = (ll(n) * a.n) % M; return *this; }
  Modulo operator+(const Modulo &a) const { Modulo res = *this; return res += a; }
  Modulo operator-(const Modulo &a) const { Modulo res = *this; return res -= a; }
  Modulo operator*(const Modulo &a) const { Modulo res = *this; return res *= a; }
};

const int mod = 1000000007;

using Mod = Modulo<mod, true>;


struct AhoCorasick {
  static const int SIZE = 128;
  struct State {
    int index, next[SIZE];
    vector<int> accept;
    State(int index) : index(index) { memset(next, -1, sizeof(next)); }
  };

  vector<State> pma;
  vector<int> lens;

  AhoCorasick(const vector<string> &str) {
    pma.clear();
    pma.push_back(State(0));
    lens.clear();

    REP(i,str.size()) {
      int t = 0;
      for (char c : str[i]) {
        if (pma[t].next[(int)c] == -1) {
          int m = pma.size();
          pma[t].next[(int)c] = m;
          pma.push_back(State(m));
        }
        t = pma[t].next[(int)c];
      }
      pma[t].accept.push_back(lens.size());
      lens.push_back(str[i].size());
    }

    queue<int> que;
    for (int c = 1; c < SIZE; c++) {
      if (pma[0].next[c] != -1) {
        pma[pma[0].next[c]].next[0] = 0;
        que.push(pma[0].next[c]);
      }
      else {
        pma[0].next[c] = 0;
      }
    }
    while (!que.empty()) {
      int t = que.front();
      que.pop();
      for (int c = 1; c < SIZE; c++) {
        if (pma[t].next[c] != -1) {
          que.push(pma[t].next[c]);
          int r = pma[t].next[0];
          while (pma[r].next[c] == -1) r = pma[r].next[0];
          pma[pma[t].next[c]].next[0] = pma[r].next[c];
          for (int i : pma[pma[r].next[c]].accept)
            pma[pma[t].next[c]].accept.push_back(i);
        }
      }
    }
  }

  int sub(int index, int c) {
    return pma[index].next[c] != -1 ?
      pma[index].next[c] :
      pma[index].next[c] = sub(pma[index].next[0], c);
  }

  pair<int,int> query(string &t, int from) {
    int index = from;
    int match = 0;
    REP(i,t.size()) {
      int c = t[i];
      index = sub(index, c);
      match += pma[index].accept.size();
    }
    return make_pair(match, index);
  }
  
};

map<string,int> dict_memo;
vector<string> dict_str;

int dict(const string &s) {
  if (dict_memo.count(s)) return dict_memo[s];
  int res = dict_str.size();
  dict_str.push_back(s);
  return dict_memo[s] = res;
}

const int BLOCK = 21;

vector<int> g[512];
Mod dp[BLOCK][512][610][2];
int is_match[512][610];
int next_node[512][610];

int main() {
  locale loc(locale(), new yes_no);
  cout << boolalpha;
  cout.imbue(loc);
  int N, M, K;
  while (cin >> N >> M >> K, N) {
    REP(i,512) g[i].clear();
    dict_str.clear();
    dict_memo.clear();
    vector<int> from(N), to(N);
    vector<string> season(K);
    REP(i,N) {
      string s, t;
      cin >> s >> t;
      from[i] = dict(s);
      to[i] = dict(t);
      g[from[i]].push_back(to[i]);
    }
    const int n = dict_str.size();
    REP(i,n) g[n].push_back(i);
    REP(i,K) cin >> season[i];
    AhoCorasick aho(season);
    REP(i,dict_str.size()) REP(j,aho.pma.size()) {
      tie(is_match[i][j], next_node[i][j]) = aho.query(dict_str[i], j);
    }
    REP(i,BLOCK) REP(j,512) REP(k,610) REP(l,2) dp[i][j][k][l] = 0;
    dp[0][n][0][0] = 1;
    // M = 2;
    REP(i,M) {
      REP(from,n+1) REP(k,aho.pma.size()) {
        // cout << i << " " << from << " " << k << " " << 0 << " " << int(dp[i%BLOCK][from][k][0]) << endl;
        // cout << i << " " << from << " " << k << " " << 1 << " " << int(dp[i%BLOCK][from][k][1]) << endl;
        for (int to: g[from]) {
          int len = dict_str[to].size();
          if (is_match[to][k] >= 2) continue;
          if (is_match[to][k]) {
            dp[(i+len)%BLOCK][to][next_node[to][k]][1] += dp[i%BLOCK][from][k][0];
          }
          else {
            dp[(i+len)%BLOCK][to][next_node[to][k]][0] += dp[i%BLOCK][from][k][0];
            dp[(i+len)%BLOCK][to][next_node[to][k]][1] += dp[i%BLOCK][from][k][1];
          }
        }
      }
      REP(j,n+1) REP(k,aho.pma.size()) REP(l,2) dp[i%BLOCK][j][k][l] = 0;
    }
    Mod res = 0;
    REP(j,n+1) REP(k,aho.pma.size()) {
      res += dp[M%BLOCK][j][k][1];
    }
    cout << int(res) << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 1870
memory_kb: 57600
final_rank: 4

code_snippet: // AOJ #2257 Sakura Poetry
// 2025.2.23

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1000000007;

struct ACNode {
    int next[26];
    int fail;
    int out;
    ACNode() : fail(0), out(0) {
        memset(next, -1, sizeof(next));
    }
};

class ACAutomaton {
public:
    vector<ACNode> nodes;
    ACAutomaton() {
        nodes.push_back(ACNode());
    }
    void insert(const string &s) {
        int cur = 0;
        for(char c: s){
            int idx = c - 'a';
            if(nodes[cur].next[idx] == -1){
                nodes[cur].next[idx] = nodes.size();
                nodes.push_back(ACNode());
            }
            cur = nodes[cur].next[idx];
        }
        nodes[cur].out++;
    }
    void build() {
        queue<int> q;
        nodes[0].fail = 0;
        for(int c=0; c<26; c++){
            int nxt = nodes[0].next[c];
            if(nxt != -1){
                nodes[nxt].fail = 0;
                q.push(nxt);
            } else nodes[0].next[c] = 0;
        }
        while(!q.empty()){
            int cur = q.front();
            q.pop();
            int f = nodes[cur].fail;
            nodes[cur].out += nodes[f].out;
            for(int c=0; c<26; c++){
                int nxt = nodes[cur].next[c];
                if(nxt != -1){
                    nodes[nxt].fail = nodes[f].next[c];
                    q.push(nxt);
                } else nodes[cur].next[c] = nodes[f].next[c];
            }
        }
    }
};

struct Word { string s; };

ACAutomaton ac;

struct SimResult {
    int next_state;
    int found;
    bool valid;
};

static vector<vector<vector<SimResult>>> memoSim;

SimResult simulateWord(const Word &word, int initState, int initFound) {
    int state = initState;
    int found = initFound;
    for (char c : word.s) {
        int idx = c - 'a';
        state = ac.nodes[state].next[idx];
        if(ac.nodes[state].out > 0) {
            if(found == 0) {
                if(ac.nodes[state].out == 1) found = 1;
                else return {0,0,false};
            } else return {0,0,false};
        }
    }
    return {state, found, true};
}

void precomputeSim(const vector<Word> &vocab) {
    int V = vocab.size();
    int A = ac.nodes.size();
    memoSim.assign(V, vector<vector<SimResult>>(2, vector<SimResult>(A)));
    for (int w = 0; w < V; w++) {
        for (int f = 0; f < 2; f++) {
            for (int st = 0; st < A; st++) {
                memoSim[w][f][st] = simulateWord(vocab[w], st, f);
            }
        }
    }
}

struct Edge { int from, to; };

struct State { int v, acState, found; };

int encodeState(const State &s, int A) {
    return ( (s.v * A) + s.acState ) * 2 + s.found;
}


int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    while(true){
        int N, M, K;
        cin >> N >> M >> K;
        if(N==0) break;

        vector<Edge> edges;
        set<string> wordSet;
        vector<pair<string, string>> rawEdges;
        for (int i=0; i<N; i++){
            string f, t;
            cin >> f >> t;
            rawEdges.push_back({f, t});
            wordSet.insert(f);
            wordSet.insert(t);
        }
        vector<Word> vocab;
        unordered_map<string,int> wordId;
        for(auto &w : wordSet){
            int id = vocab.size();
            vocab.push_back({w});
            wordId[w] = id;
        }

        vector<vector<int>> adj(vocab.size());
        for(auto &p: rawEdges){
            int u = wordId[p.first], v = wordId[p.second];
            adj[u].push_back(v);
        }

        vector<string> seasonWords(K);
        ac.nodes.clear();
        ac.nodes.push_back(ACNode());
        for (int i=0; i<K; i++){
            cin >> seasonWords[i];
            ac.insert(seasonWords[i]);
        }
        ac.build();

        precomputeSim(vocab);

        int A = ac.nodes.size();
        int V = vocab.size();

        vector<unordered_map<int, int>> dp(M+1);

        for (int v=0; v<V; v++){
            int l = vocab[v].s.size();
            if(l > M) continue;
            SimResult res = memoSim[v][0][0];
            if(!res.valid) continue;
            State st = {v, res.next_state, res.found};
            int code = encodeState(st, A);
            dp[l][code] = (dp[l][code] + 1) % MOD;
        }

        for (int len = 0; len <= M; len++){
            if(dp[len].empty()) continue;
            for(auto &entry : dp[len]){
                int ways = entry.second;
                int code = entry.first;
                int found = code % 2; code /= 2;
                int acState = code % A; code /= A;
                int v = code;
                State curState = {v, acState, found};

                for (int nv : adj[curState.v]) {
                    int addLen = vocab[nv].s.size();
                    if(len + addLen > M) continue;
                    SimResult res = memoSim[nv][curState.found][curState.acState];
                    if(!res.valid) continue;
                    State nxt = {nv, res.next_state, res.found};
                    int code2 = encodeState(nxt, A);
                    dp[len + addLen][code2] = (dp[len + addLen][code2] + ways) % MOD;
                }
            }
        }

        long long ans = 0;
        for(auto &entry : dp[M]){
            int code = entry.first;
            int found = code & 1;
            if(found == 1) {
                ans = (ans + entry.second) % MOD;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1200
memory_kb: 150664
final_rank: 6

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

template < class T > vector< T >& operator++(vector< T >& a) { for(T& x : a) x++; return a; }
template < class T > vector< T >& operator--(vector< T >& a) { for(T& x : a) x--; return a; }
template < class T > vector< T >  operator++(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x++; return res; }
template < class T > vector< T >  operator--(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x--; return res; }

} // namespace macro

using namespace macro;
#line 2 "cp-library/src/string/aho_corasick.hpp"

struct aho_corasick {
    static constexpr int C_SIZE = 26;
    static constexpr int C_BEGIN = 'a';
    static constexpr int ROOT = 0;
    struct node {
        array<int, C_SIZE> to = {};
        vector<int> ids; // このノードでマッチする文字列のIDリスト
        int fail = ROOT; // 失敗時の遷移先
        int drct = ROOT; // suffixでマッチする遷移先
        node() { to.fill(-1); }
    };
    vector<node> nodes;
    vector<string> patterns;
    aho_corasick() : nodes(1) {}

    int insert(const string& s) {
        int v = ROOT;
        for(char c : s) {
            const int k = c - C_BEGIN;
            if(nodes[v].to[k] == -1) {
                nodes[v].to[k] = nodes.size();
                nodes.push_back(node());
            }
            v = nodes[v].to[k];
        }
        nodes[v].ids.push_back(patterns.size());
        patterns.push_back(s);
        return v;
    }

    int next(int v, char c) {
        const int k = c - C_BEGIN;
        while(nodes[v].to[k] == -1 and v != ROOT) v = nodes[v].fail;
        return nodes[v].to[k] != -1 ? nodes[v].to[k] : ROOT;
    }

    void build() {
        std::queue<int> q;
        for(int v : nodes[ROOT].to) if(v != -1) q.push(v);
        while(not q.empty()) {
            int v = q.front(); q.pop();
            int fail = nodes[v].fail;
            for(int k = 0; k < C_SIZE; k++) {
                int nv = nodes[v].to[k];
                if(nv != -1) {
                    q.push(nv);
                    nodes[nv].fail = next(fail, k + C_BEGIN);
                }
            }
            nodes[v].drct = (nodes[fail].ids.empty() ? nodes[fail].drct : fail);
        }
    }

    // v で完成している (受理される) 
    bool accept(int v) {
        return nodes[v].drct != ROOT or not nodes[v].ids.empty();
    }
    vector<int> match(int v) {
        vector<int> res;
        while(v != ROOT) {
            for(int id : nodes[v].ids) res.push_back(id);
            v = nodes[v].drct;
        }
        return res;
    }
    vector<vector<int>> search(const string& s) {
        vector<vector<int>> res;
        int now = ROOT;
        for(char c : s) {
            now = next(now, c);
            res.emplace_back(match(now));
        }
        return res;
    }
};
#line 2 "cp-library/src/number/modint.hpp"
struct modinfo { uint mod, root, isprime; };
template < modinfo const &ref >
struct modint {
    static constexpr uint const &mod = ref.mod;
    static constexpr uint const &root = ref.root;
    static constexpr uint const &isprime = ref.isprime;
    uint v = 0;
    constexpr modint& s(uint v) { this->v = v < mod ? v : v - mod; return *this; }
    constexpr modint(ll v = 0) { s(v % mod + mod); }
    modint operator-() const { return modint() - *this; }
    modint& operator+=(const modint& rhs) { return s(v + rhs.v); }
    modint& operator-=(const modint& rhs) { return s(v + mod - rhs.v); }
    modint& operator*=(const modint& rhs) { v = ull(v) * rhs.v % mod; return *this; }
    modint& operator/=(const modint& rhs) { return *this *= inv(rhs); }
    modint operator+(const modint& rhs) const { return modint(*this) += rhs; }
    modint operator-(const modint& rhs) const { return modint(*this) -= rhs; }
    modint operator*(const modint& rhs) const { return modint(*this) *= rhs; }
    modint operator/(const modint& rhs) const { return modint(*this) /= rhs; }
    friend modint pow(modint x, ll n) { modint res(1); while(n > 0) { if(n & 1) res *= x; x *= x; n >>= 1; } return res; }
    friend modint inv(modint v) {
        if(isprime) {
            return pow(v, mod - 2);
        } else {
            ll a = v.v, b = modint::mod, x = 1, y = 0, t;
            while(b > 0) { t = a / b; swap(a -= t * b, b); swap(x -= t * y, y); }
            return modint(x);
        }
    }
    friend modint operator+(int x, const modint& y) { return modint(x) + y; }
    friend modint operator-(int x, const modint& y) { return modint(x) - y; }
    friend modint operator*(int x, const modint& y) { return modint(x) * y; }
    friend modint operator/(int x, const modint& y) { return modint(x) / y; }
    friend istream& operator>>(istream& is, modint& m) { ll x; is >> x; m = modint(x); return is; }
    friend ostream& operator<<(ostream& os, const modint& m) { return os << m.v; }
    bool operator==(const modint& r) const { return v == r.v; }
    bool operator!=(const modint& r) const { return v != r.v; }
    static uint get_mod() { return mod; }
    static int is_prime() { return isprime; }
};
constexpr modinfo base998244353 { 998244353, 3, 1 };
constexpr modinfo base1000000007 { 1000000007, 0, 1 };
using mint998244353 = modint< base998244353 >;
using mint1000000007 = modint< base1000000007 >;
#line 5 "A.cpp"
using mint = mint1000000007;

mint solve(int N, int M, int K) {
    int word_cnt = 0;
    vector<string> word;
    map<string, int> w_id;
    vector<vector<int>> g;
    {
        word.push_back("");
        w_id[""] = word_cnt++;
        g.push_back({});
    }
    for(int _ : rep(N)) {
        string from_s = in(), to_s = in();
        if(!w_id.count(from_s)) word.push_back(from_s), w_id[from_s] = word_cnt++, g.push_back({});
        if(!w_id.count(to_s)) word.push_back(to_s), w_id[to_s] = word_cnt++, g.push_back({});
        const int from = w_id[from_s], to = w_id[to_s];
        g[from].push_back(to);
    }
    for(int wi : rep(1, word_cnt)) g[0].push_back(wi);

    vector<string> sw = in(K);
    aho_corasick ac;
    for(string& s : sw) ac.insert(s);
    ac.build();
    const int node_size = ac.nodes.size();

    vector dp(M + 1, vector(word_cnt, vector(2, map<int, mint>{})));
    dp[0][0][0][ac.ROOT] = 1;

    for(int m : rep(M)) {
        for(int from : rep(word_cnt)) for(int to : g[from]) {
            const string& s = word[to];
            if(not(m + s.size() <= M)) continue;
            for(int sw_cnt : {0, 1}) if(not dp[m][from][sw_cnt].empty()) {
                for(int ni : rep(node_size)) if(dp[m][from][sw_cnt].count(ni)) {
                    int n_sw_cnt = sw_cnt;
                    int n_ni = ni;
                    bool ok = [&] {
                        for(char c : s) {
                            n_ni = ac.next(n_ni, c);
                            if(ac.accept(n_ni)) {
                                n_sw_cnt += ac.match(n_ni).size();
                                if(n_sw_cnt > 1) return false;
                            }
                        }
                        return true;
                    }();
                    if(ok) {
                        dp[m + s.size()][to][n_sw_cnt][n_ni] += dp[m][from][sw_cnt][ni];
                    }
                }
            }
        }
    }

    mint ans = 0;
    for(int wi : rep(word_cnt)) {
        for(int ni : rep(node_size)) {
            ans += dp[M][wi][1][ni];
        }
    }
    return ans;
}

int main() {
    while(true) {
        int N = in(), M = in(), K = in();
        if(make_tuple(N, M, K) == make_tuple(0, 0, 0)) return 0;
        print(solve(N, M, K));
    }
}
accuracy: 1
time_ms: 6380
memory_kb: 153504
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t) - 1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T>
bool chmax(T& a, const T& b) {
    return a < b ? (a = b, 1) : 0;
}
template <typename T>
bool chmin(T& a, const T& b) {
    return a > b ? (a = b, 1) : 0;
}

template <int m>
class Modint {
    using mint = Modint;
    static_assert(m > 0, "Modulus must be positive");

   public:
    static constexpr int mod() { return m; }

    constexpr Modint(long long y = 0) : x(y >= 0 ? y % m : (y % m + m) % m) {}

    constexpr int val() const { return x; }

    constexpr mint& operator+=(const mint& r) {
        if ((x += r.x) >= m) x -= m;
        return *this;
    }
    constexpr mint& operator-=(const mint& r) {
        if ((x += m - r.x) >= m) x -= m;
        return *this;
    }
    constexpr mint& operator*=(const mint& r) {
        x = static_cast<int>(1LL * x * r.x % m);
        return *this;
    }
    constexpr mint& operator/=(const mint& r) { return *this *= r.inv(); }

    constexpr bool operator==(const mint& r) const { return x == r.x; }

    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint(-x); }

    constexpr friend mint operator+(const mint& l, const mint& r) {
        return mint(l) += r;
    }
    constexpr friend mint operator-(const mint& l, const mint& r) {
        return mint(l) -= r;
    }
    constexpr friend mint operator*(const mint& l, const mint& r) {
        return mint(l) *= r;
    }
    constexpr friend mint operator/(const mint& l, const mint& r) {
        return mint(l) /= r;
    }

    constexpr mint inv() const {
        int a = x, b = m, u = 1, v = 0;
        while (b > 0) {
            int t = a / b;
            std::swap(a -= t * b, b);
            std::swap(u -= t * v, v);
        }
        return mint(u);
    }

    constexpr mint pow(long long n) const {
        mint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend std::ostream& operator<<(std::ostream& os, const mint& r) {
        return os << r.x;
    }

    friend std::istream& operator>>(std::istream& is, mint& r) {
        long long t;
        is >> t;
        r = mint(t);
        return is;
    }

   private:
    int x;
};

class AhoCorasick {
   public:
    struct Node {
        std::map<char, int> ch;
        std::vector<int> accept;
        int link = -1;
        int cnt = 0;

        Node() = default;
    };

    std::vector<Node> states;
    std::map<int, int> accept_state;

    explicit AhoCorasick() : states(1) {}

    int size() const { return states.size(); }

    void insert(const std::string& s, int id = -1) {
        int i = 0;
        for (char c : s) {
            if (!states[i].ch.count(c)) {
                states[i].ch[c] = states.size();
                states.emplace_back();
            }
            i = states[i].ch[c];
        }
        ++states[i].cnt;
        states[i].accept.push_back(id);
        accept_state[id] = i;
    }

    void clear() {
        states.clear();
        states.emplace_back();
    }

    int get_next(int i, char c) const {
        while (i != -1 && !states[i].ch.count(c)) i = states[i].link;
        return i != -1 ? states[i].ch.at(c) : 0;
    }

    void build() {
        std::queue<int> que;
        que.push(0);
        while (!que.empty()) {
            int i = que.front();
            que.pop();

            for (auto [c, j] : states[i].ch) {
                states[j].link = get_next(states[i].link, c);
                states[j].cnt += states[states[j].link].cnt;

                auto& a = states[j].accept;
                auto& b = states[states[j].link].accept;
                std::vector<int> accept;
                // std::ranges::set_union(a, b, std::back_inserter(accept));
                std::set_union(a.begin(), a.end(), b.begin(), b.end(),
                               std::back_inserter(accept));
                a = accept;

                que.push(j);
            }
        }
    }

    long long count(const std::string& str) const {
        long long ret = 0;
        int i = 0;
        for (auto c : str) {
            i = get_next(i, c);
            ret += states[i].cnt;
        }
        return ret;
    }

    long long count(int i) const { return states[i].cnt; }

    // list of (id, index)
    std::vector<std::pair<int, int>> match(const std::string& str) const {
        std::vector<std::pair<int, int>> ret;
        int i = 0;
        for (int k = 0; k < (int)str.size(); ++k) {
            char c = str[k];
            i = get_next(i, c);
            for (auto id : states[i].accept) {
                ret.emplace_back(id, k);
            }
        }
        return ret;
    }
};

using mint = Modint<(int)1e9 + 7>;

map<pair<int, int>, mint> dp[501][2];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (true) {
        int N, M, K;
        cin >> N >> M >> K;
        if (N == 0) break;
        map<string, int> idx;
        vector<string> strs;
        vector<vector<int>> G;
        rep(_, 0, N) {
            string s, t;
            cin >> s >> t;
            if (s.size() > M || t.size() > M) continue;
            if (idx.count(s) == 0) {
                idx[s] = strs.size();
                strs.push_back(s);
                G.emplace_back();
            }
            if (idx.count(t) == 0) {
                idx[t] = strs.size();
                strs.push_back(t);
                G.emplace_back();
            }
            G[idx[s]].push_back(idx[t]);
        }
        AhoCorasick aho;
        rep(i, 0, K) {
            string s;
            cin >> s;
            aho.insert(s);
        }
        aho.build();
        rep(len, 0, M + 1) rep(a, 0, 2) dp[len][a].clear();
        rep(i, 0, strs.size()) {
            int k = 0, a = 0;
            for (char c : strs[i]) {
                k = aho.get_next(k, c);
                a += aho.count(k);
            }
            if (a <= 1) {
                dp[strs[i].size()][a][{i, k}] = 1;
            }
        }
        rep(len, 0, M + 1) rep(a, 0, 2) for (auto& p : dp[len][a]) {
            auto [i, k] = p.first;
            for (int j : G[i]) {
                int nlen = len + strs[j].size();
                if (nlen > M) continue;
                int nk = k, na = a;
                for (char c : strs[j]) {
                    nk = aho.get_next(nk, c);
                    na += aho.count(nk);
                }
                if (na <= 1) {
                    dp[nlen][na][{j, nk}] += p.second;
                }
            }
        }
        mint ans = 0;
        for (auto& p : dp[M][1]) ans += p.second;
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 3810
memory_kb: 201060
final_rank: 17

code_snippet: #include <bits/stdc++.h>

void debug(std::string S = "Hello") {
    std::cout << S << std::endl;
}

struct Comp {
    std::vector<std::string> S;
    Comp() = default;
    void push_back(const std::string& s) {
        S.push_back(s);
    }
    void build() {
        std::sort(S.begin(), S.end());
        S.erase(std::unique(S.begin(), S.end()), S.end());
    }
    int size() const {
        return (int)S.size();
    }
    const std::string& inv(int i) const {
        assert(i < size());
        return S[i];
    }
    int at(const std::string& s) const {
        auto it{std::lower_bound(S.begin(), S.end(), s)};
        assert(it != S.end());
        assert(*it == s);
        return (int)std::distance(S.begin(), it);
    }
};

struct Node {
    std::array<int, 26> ch;
    int par{-1}, label{-1}, suf{-1}, cnt{};
    Node() {
        ch.fill(-1);
    }
    Node(int p, int l) : ch{}, par{p}, label{l} {
        ch.fill(-1);
    }
};

struct Trie {
    std::vector<Node> dat;    
    Trie() = default;
    void insert(const std::string& s) {
        int v{};
        for (int i{} ; i < (int)s.size() ; i++) {
            int label{s[i] - 'a'};
            if (dat[v].ch[label] == -1) {
                int x{(int)dat.size()};
                dat.emplace_back(v, label);
                dat[v].ch[label] = x;
            }
            v = dat[v].ch[label];
        }
        dat[v].cnt = 1;
    }
    void makeSuffixLink() {
        dat[0].suf = 0;
        std::queue<int> que;
        for (int i{} ; i < 26 ; i++) {
            if (dat[0].ch[i] != -1) {
                que.emplace(dat[0].ch[i]);
            }
        }
        while (que.size()) {
            auto v{que.front()};
            que.pop();
            int suf{dat[dat[v].par].suf};
            assert(0 <= suf and suf < (int)dat.size());
            int label{dat[v].label};
            // std::cout << suf << ' ' << dat[suf].suf << std::endl;
            while (dat[suf].ch[label] == -1 and dat[suf].suf != suf) {
                suf = dat[suf].suf;
            }
            if (dat[suf].ch[label] == -1) {
                assert(suf == 0);
            }
            else if (dat[suf].ch[label] == v) {
                assert(suf == 0);
            }
            else {
                suf = dat[suf].ch[label];
            }
            dat[v].suf = suf;
            dat[v].cnt += dat[suf].cnt;
            for (int i{} ; i < 26 ; i++) {
                if (dat[v].ch[i] == -1) continue;
                que.emplace(dat[v].ch[i]);
            }
        }
    }
    Trie(const std::vector<std::string>& S) : dat(1) {
        for (const auto& s : S) insert(s);
        // debug("insert end");
        makeSuffixLink();
        // debug("suflink end");
    }
    std::pair<int, int> moved(int v, char c) const {
        // debug("try " + std::string{c});
        assert(0 <= v and v < (int)dat.size());
        assert('a' <= c and c <= 'z');
        int label{c - 'a'};
        while (dat[v].ch[label] == -1 and dat[v].suf != v) {
            v = dat[v].suf;
        }
        if (dat[v].ch[label] == -1) {
            assert(v == 0);
        }
        else {
            v = dat[v].ch[label];
        }
        return { v, dat[v].cnt };
    }
    std::pair<int, int> moved(int v, const std::string& s) const {
        // debug("try " + s);
        std::pair<int, int> res{v, 0};
        for (auto c : s) {
            auto [x, y]{moved(res.first, c)};
            res.first = x;
            res.second += y;
        }
        return res;
    }
    int size() const {
        return (int)dat.size();
    }
};

constexpr long long mod{1000000007};

bool solve() {
    int N, M, K;
    std::cin >> N >> M >> K;
    if (N == 0) return false;
    std::vector<std::string> from(N), to(N);
    Comp comp;
    for (int i{} ; i < N ; i++) {
        std::cin >> from[i] >> to[i];
        comp.push_back(from[i]);
        comp.push_back(to[i]);
    }
    comp.build();
    std::vector<std::vector<int>> g(comp.size());
    for (int i{} ; i < N ; i++) {
        g[comp.at(from[i])].push_back(comp.at(to[i]));
    }
    std::vector<std::string> S(K);
    for (auto& s : S) std::cin >> s;
    Trie aho(S);
    using qt = std::tuple<int, int, int, int>; // len, cnt, v, cur
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    auto f{[&](int len, int cnt, int v, int cur) -> long long {
        assert(0 <= len and len <= M);
        assert(0 <= cnt and cnt <= 1);
        assert(0 <= v and v < (int)aho.size());
        assert(0 <= cur and cur < (int)comp.size());
        long long res{len};
        res = res * (long long)2 + cnt;
        res = res * (long long)aho.size() + v;
        res = res * (long long)comp.size() + cur;
        return res;
    }};
    std::map<long long, int> dp;
    for (int i{} ; i < (int)comp.size() ; i++) {
        const std::string& str{comp.inv(i)};
        if ((int)str.size() > M) continue;
        auto [v, cnt]{aho.moved(0, str)};
        if (cnt >= 2) continue;
        dp[f((int)str.size(), cnt, v, i)] = 1;
        que.emplace((int)str.size(), cnt, v, i);
    }
    while (que.size()) {
        auto [len, cnt, v, cur]{que.top()};
        que.pop();
        auto it{dp.find(f(len, cnt, v, cur))};
        assert(it != dp.end());
        for (auto next : g[cur]) {
            const std::string& str{comp.inv(next)};
            if (len + (int)str.size() > M) continue;
            auto [x, add]{aho.moved(v, str)};
            if (cnt + add >= 2) continue;
            long long key{f(len + (int)str.size(), cnt + add, x, next)};
            if (dp.find(key) == dp.end()) {
                que.emplace(len + (int)str.size(), cnt + add, x, next);
            }
            dp[key] += it->second;
            if (dp[key] >= mod) dp[key] -= mod;
        }
    }
    int ans{};
    for (int v{} ; v < (int)aho.size() ; v++) {
        for (int cur{} ; cur < (int)comp.size() ; cur++) {
            auto it{dp.find(f(M, 1, v, cur))};
            if (it != dp.end()) {
                ans += it->second;
                if (ans >= mod) ans -= mod;
            }
        }
    }
    std::cout << ans << '\n';
    return true;
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    while (solve()) ;
}
accuracy: 1
time_ms: 6800
memory_kb: 201700
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repd(i,a,b) for (ll i=(a);i<(b);i++)
#define rep(i,n) repd(i,0,n)
#define all(x) (x).begin(),(x).end()
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
typedef long long ll;
typedef pair<ll,ll> P;
typedef vector<ll> vec;
using Graph = vector<vector<ll>>;
const long long INF = 1LL<<60;
const long long MOD = 1000000007;
 
// Aho-Corasick
// https://youtu.be/BYoRvdgI5EU?t=9633
struct Aho {
  using MP = unordered_map<char,int>;
  vector<MP> to;
  vector<int> cnt, fail;
  Aho(): to(1), cnt(1) {}
  int add(const string& s) {
    int v = 0;
    for (char c : s) {
      if (!to[v].count(c)) {
        to[v][c] = to.size();
        to.push_back(MP());
        cnt.push_back(0);
      }
      v = to[v][c];
    }
    cnt[v]++;
    return v;
  }
  void init() {
    fail = vector<int>(to.size(), -1);
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
      int v = q.front(); q.pop();
      for (auto [c,u] : to[v]) {
        fail[u] = (*this)(fail[v],c);
        cnt[u] += cnt[fail[u]];
        q.push(u);
      }
    }
  }
  int operator()(int v, char c) const {
    while (v != -1) {
      auto it = to[v].find(c);
      if (it != to[v].end()) return it->second;
      v = fail[v];
    }
    return 0;
  }
  int operator[](int v) const { return cnt[v];}
};

// auto mod int
// https://youtu.be/L8grWxBlIZ4?t=9858
// https://youtu.be/ERZuLAxZffQ?t=4807 : optimize
// https://youtu.be/8uowVvQ_-Mo?t=1329 : division
const int mod = 1000000007;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x=0):x((x%mod+mod)%mod){}
  mint operator-() const { return mint(-x);}
  mint& operator+=(const mint a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator-=(const mint a) {
    if ((x += mod-a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
  mint operator+(const mint a) const { return mint(*this) += a;}
  mint operator-(const mint a) const { return mint(*this) -= a;}
  mint operator*(const mint a) const { return mint(*this) *= a;}
  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }

  // for prime mod
  mint inv() const { return pow(mod-2);}
  mint& operator/=(const mint a) { return *this *= a.inv();}
  mint operator/(const mint a) const { return mint(*this) /= a;}
};
istream& operator>>(istream& is, mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}


int main()
{  
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,k;
    while(cin>>n>>m>>k){
      if(n==0&&m==0&&k==0)break;
      map<string,int> mp;
      Graph g;
      vector<string> memo;
      vector<string> F(n),G(n);
      set<int> set;
      rep(i,n){
        cin>>F[i]>>G[i];
        if(!mp.count(F[i])){mp[F[i]]=mp.size();g.push_back({});memo.push_back(F[i]);}
        set.insert(mp[F[i]]);
      }
      rep(i,n){
        if(!mp.count(G[i])){mp[G[i]]=mp.size();memo.push_back(G[i]);}
        g[mp[F[i]]].push_back(mp[G[i]]);
        set.insert(mp[G[i]]);
      }
      Aho aho;
      rep(i,k){
        string s;cin>>s;
        aho.add(s);
      }
      aho.init();
      int sz=aho.to.size();
      int sz2=g.size();
      mint ans=0;
      vector dp(21,vector(sz,vector(sz2,vector<mint>(2))));
      while(set.size()){
        auto x=*set.begin();
        set.erase(set.begin());
        ll i=0,j=0,k=x,l=0;
        for(char c:memo[x]){
          i++;
          j=aho(j,c);
          l+=aho[j];
        }
        if(l>1||i>m)continue;
        if(i==m&&l==1)ans+=1;
        if(k<g.size())dp[i][j][k][l]+=1;
      }
      rep(i,m){
        rep(j,sz){
          rep(k,sz2){
            rep(l,2){
              if(dp[i%21][j][k][l].x==0)continue;
              for(int nk:g[k]){
                if(nk>=g.size()&&m-i>20)continue;
                ll ni=i%21,nj=j,nl=l;
                for(char c:memo[nk]){
                  ni++;
                  nj=aho(nj,c);
                  nl+=aho[nj];
                }
                if(nl>1)continue;
                if(m-i<=20&&ni%21==m%21&&nl==1){ans+=dp[i%21][j][k][l];continue;}
                if(nk>=g.size())continue;
                dp[ni%21][nj][nk][nl]+=dp[i%21][j][k][l];
                //cout<<i%21<<" "<<j<<" "<<k<<" "<<l<<" "<<dp[i%21][j][k][l]<<endl;
                //cout<<ni%21<<" "<<nj<<" "<<nk<<" "<<nl<<" "<<dp[ni%21][nj][nk][nl]<<endl;
              }
              dp[i%21][j][k][l]=0;
            }
          }
        }
      }
      cout<<ans<<'\n';
    }
    return 0;
}
accuracy: 1
time_ms: 5840
memory_kb: 181500
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;

const int MOD = 1000000007;

class string_hash {
private:
	int n;
	vector<array<int, 2> > pw;
	vector<array<int, 2> > h;
public:
	static constexpr int mod0 = 970071317;
	static constexpr int mod1 = 979598959;
	string_hash() : n(0), pw(vector<array<int, 2> >()), h(vector<array<int, 2> >()) {}
	string_hash(const string& s) : n(s.size()) {
		pw.resize(n + 1);
		h.resize(n + 1);
		pw[0] = { 1, 1 };
		h[0] = { 0, 0 };
		for (int i = 0; i < n; i++) {
			pw[i + 1][0] = 1LL * pw[i][0] * 311 % mod0;
			pw[i + 1][1] = 1LL * pw[i][1] * 359 % mod1;
			h[i + 1][0] = (1LL * h[i][0] * 311 + s[i]) % mod0;
			h[i + 1][1] = (1LL * h[i][1] * 359 + s[i]) % mod1;
		}
	}
	uint64_t hash(int l, int r) const {
		assert(0 <= l && l <= r && r <= n);
		int v0 = (h[r][0] - 1LL * h[l][0] * pw[r - l][0] % mod0 + mod0) % mod0;
		int v1 = (h[r][1] - 1LL * h[l][1] * pw[r - l][1] % mod1 + mod1) % mod1;
		return uint64_t(v0) * mod1 + v1;
	}
};

int solve(int N, int M, int K, const vector<string>& A, const vector<string>& B, const vector<string>& C) {
	vector<string> D = { string() };
	for (int i = 0; i < K; i++) {
		for (int j = 1; j <= C[i].size(); j++) {
			D.push_back(C[i].substr(0, j));
		}
	}
	sort(D.begin(), D.end(), [](const string& s1, const string& s2) {
		return s1.size() != s2.size() ? s1.size() < s2.size() : s1 < s2;
	});
	D.erase(unique(D.begin(), D.end()), D.end());
	int Z = D.size();
	vector<uint64_t> CH(K);
	for (int i = 0; i < K; i++) {
		CH[i] = string_hash(C[i]).hash(0, C[i].size());
	}
	vector<uint64_t> DH(Z);
	for (int i = 0; i < Z; i++) {
		DH[i] = string_hash(D[i]).hash(0, D[i].size());
	}
	auto calc = [&](int state, const string& tail) -> pair<int, int> {
		// returns (state, # of new seasons)
		string s = D[state] + tail;
		string_hash h(s);
		int seasons = 0;
		for (int i = 0; i < int(s.size()); i++) {
			for (int j = 0; j < K; j++) {
				int r = i + C[j].size();
				if (D[state].size() < r && r <= s.size() && h.hash(i, r) == CH[j]) {
					seasons += 1;
				}
			}
		}
		int nstate = 0;
		for (int i = 1; i < Z; i++) {
			if (D[i].size() <= s.size() && h.hash(s.size() - D[i].size(), s.size()) == DH[i]) {
				nstate = i;
			}
		}
		return make_pair(nstate, seasons);
	};
	vector<string> E(2 * N + 1);
	for (int i = 0; i < N; i++) {
		E[2 * i + 0] = A[i];
		E[2 * i + 1] = B[i];
	}
	sort(E.begin(), E.end());
	E.erase(unique(E.begin(), E.end()), E.end());
	int W = E.size();
	vector<vector<int> > G(W);
	for (int i = 0; i < N; i++) {
		int pa = lower_bound(E.begin(), E.end(), A[i]) - E.begin();
		int pb = lower_bound(E.begin(), E.end(), B[i]) - E.begin();
		G[pa].push_back(pb);
	}
	for (int i = 1; i < W; i++) {
		G[0].push_back(i);
	}
	vector<vector<pair<int, int> > > precalc(W, vector<pair<int, int> >(Z));
	for (int i = 0; i < W; i++) {
		for (int j = 0; j < Z; j++) {
			precalc[i][j] = calc(j, E[i]);
		}
	}
	int maxlen = 0;
	for (int i = 0; i < W; i++) {
		maxlen = max(maxlen, int(E[i].size()));
	}
	int cycle = maxlen + 1;
	vector<vector<vector<array<int, 2> > > > dp(cycle, vector<vector<array<int, 2> > >(W, vector<array<int, 2> >(Z)));
	dp[0][0][0][0] = 1;
	for (int i = 0; i < M; i++) {
		for (int j = 0; j < W; j++) {
			for (int k = 0; k < Z; k++) {
				for (int l = 0; l < 2; l++) {
					for (int v : G[j]) {
						int len = i + E[v].size();
						int ns = precalc[v][k].first;
						int nc = l + precalc[v][k].second;
						if (len <= M && nc <= 1) {
							dp[len % cycle][v][ns][nc] += dp[i % cycle][j][k][l];
							dp[len % cycle][v][ns][nc] %= MOD;
						}
					}
				}
			}
		}
		for (int j = 0; j < W; j++) {
			for (int k = 0; k < Z; k++) {
				dp[i % cycle][j][k][0] = 0;
				dp[i % cycle][j][k][1] = 0;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i < W; i++) {
		for (int j = 0; j < Z; j++) {
			ans += dp[M % cycle][i][j][1];
			ans %= MOD;
		}
	}
	return ans;
}

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	while (true) {
		int N, M, K;
		cin >> N >> M >> K;
		if (N == 0 && M == 0 && K == 0) {
			break;
		}
		vector<string> A(N), B(N), C(K);
		for (int i = 0; i < N; i++) {
			cin >> A[i] >> B[i];
		}
		for (int i = 0; i < K; i++) {
			cin >> C[i];
		}
		int ans = solve(N, M, K, A, B, C);
		cout << ans << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 7060
memory_kb: 56628
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=605;
const ll INF=1LL<<62;

//modintのみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {
    
    namespace internal {
        
#ifndef _MSC_VER
        template <class T>
        using is_signed_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value ||
        std::is_same<T, __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int128 =
        typename std::conditional<std::is_same<T, __uint128_t>::value ||
        std::is_same<T, unsigned __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using make_unsigned_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value,
        __uint128_t,
        unsigned __int128>;
        
        template <class T>
        using is_integral = typename std::conditional<std::is_integral<T>::value ||
        is_signed_int128<T>::value ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                         std::is_signed<T>::value) ||
        is_signed_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<(is_integral<T>::value &&
                                   std::is_unsigned<T>::value) ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<
        is_signed_int128<T>::value,
        make_unsigned_int128<T>,
        typename std::conditional<std::is_signed<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type>::type;
        
#else
        
        template <class T> using is_integral = typename std::is_integral<T>;
        
        template <class T>
        using is_signed_int =
        typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<is_integral<T>::value &&
        std::is_unsigned<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<is_signed_int<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type;
        
#endif
        
        template <class T>
        using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
        
        template <class T>
        using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
        
        template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
        
    }  // namespace internal
    
}  // namespace atcoder

#include <utility>

namespace atcoder {
    
    namespace internal {
        
        constexpr long long safe_mod(long long x, long long m) {
            x %= m;
            if (x < 0) x += m;
            return x;
        }
        
        struct barrett {
            unsigned int _m;
            unsigned long long im;
            
            barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
            
            unsigned int umod() const { return _m; }
            
            unsigned int mul(unsigned int a, unsigned int b) const {
                
                unsigned long long z = a;
                z *= b;
#ifdef _MSC_VER
                unsigned long long x;
                _umul128(z, im, &x);
#else
                unsigned long long x =
                (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
                unsigned int v = (unsigned int)(z - x * _m);
                if (_m <= v) v += _m;
                return v;
            }
        };
        
        constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
            if (m == 1) return 0;
            unsigned int _m = (unsigned int)(m);
            unsigned long long r = 1;
            unsigned long long y = safe_mod(x, m);
            while (n) {
                if (n & 1) r = (r * y) % _m;
                y = (y * y) % _m;
                n >>= 1;
            }
            return r;
        }
        
        constexpr bool is_prime_constexpr(int n) {
            if (n <= 1) return false;
            if (n == 2 || n == 7 || n == 61) return true;
            if (n % 2 == 0) return false;
            long long d = n - 1;
            while (d % 2 == 0) d /= 2;
            for (long long a : {2, 7, 61}) {
                long long t = d;
                long long y = pow_mod_constexpr(a, t, n);
                while (t != n - 1 && y != 1 && y != n - 1) {
                    y = y * y % n;
                    t <<= 1;
                }
                if (y != n - 1 && t % 2 == 0) {
                    return false;
                }
            }
            return true;
        }
        template <int n> constexpr bool is_prime = is_prime_constexpr(n);
        
        constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
            a = safe_mod(a, b);
            if (a == 0) return {b, 0};
            
            long long s = b, t = a;
            long long m0 = 0, m1 = 1;
            
            while (t) {
                long long u = s / t;
                s -= t * u;
                m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b
                
                
                auto tmp = s;
                s = t;
                t = tmp;
                tmp = m0;
                m0 = m1;
                m1 = tmp;
            }
            if (m0 < 0) m0 += b / s;
            return {s, m0};
        }
        
        constexpr int primitive_root_constexpr(int m) {
            if (m == 2) return 1;
            if (m == 167772161) return 3;
            if (m == 469762049) return 3;
            if (m == 754974721) return 11;
            if (m == 998244353) return 3;
            int divs[20] = {};
            divs[0] = 2;
            int cnt = 1;
            int x = (m - 1) / 2;
            while (x % 2 == 0) x /= 2;
            for (int i = 3; (long long)(i)*i <= x; i += 2) {
                if (x % i == 0) {
                    divs[cnt++] = i;
                    while (x % i == 0) {
                        x /= i;
                    }
                }
            }
            if (x > 1) {
                divs[cnt++] = x;
            }
            for (int g = 2;; g++) {
                bool ok = true;
                for (int i = 0; i < cnt; i++) {
                    if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return g;
            }
        }
        template <int m> constexpr int primitive_root = primitive_root_constexpr(m);
        
    }  // namespace internal
    
}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {
    
    namespace internal {
        
        struct modint_base {};
        struct static_modint_base : modint_base {};
        
        template <class T> using is_modint = std::is_base_of<modint_base, T>;
        template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;
        
    }  // namespace internal
    
    template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
    struct static_modint : internal::static_modint_base {
        using mint = static_modint;
        
    public:
        static constexpr int mod() { return m; }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        static_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        static_modint(T v) {
            long long x = (long long)(v % (long long)(umod()));
            if (x < 0) x += umod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        static_modint(T v) {
            _v = (unsigned int)(v % umod());
        }
        static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v -= rhs._v;
            if (_v >= umod()) _v += umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            unsigned long long z = _v;
            z *= rhs._v;
            _v = (unsigned int)(z % umod());
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            if (prime) {
                assert(_v);
                return pow(umod() - 2);
            } else {
                auto eg = internal::inv_gcd(_v, m);
                assert(eg.first == 1);
                return eg.second;
            }
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static constexpr unsigned int umod() { return m; }
        static constexpr bool prime = internal::is_prime<m>;
    };
    
    template <int id> struct dynamic_modint : internal::modint_base {
        using mint = dynamic_modint;
        
    public:
        static int mod() { return (int)(bt.umod()); }
        static void set_mod(int m) {
            assert(1 <= m);
            bt = internal::barrett(m);
        }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        dynamic_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            long long x = (long long)(v % (long long)(mod()));
            if (x < 0) x += mod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            _v = (unsigned int)(v % mod());
        }
        dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v += mod() - rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            _v = bt.mul(_v, rhs._v);
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            auto eg = internal::inv_gcd(_v, mod());
            assert(eg.first == 1);
            return eg.second;
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static internal::barrett bt;
        static unsigned int umod() { return bt.umod(); }
    };
    template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;
    
    using modint998244353 = static_modint<998244353>;
    using modint1000000007 = static_modint<1000000007>;
    using modint = dynamic_modint<-1>;
    
    namespace internal {
        
        template <class T>
        using is_static_modint = std::is_base_of<internal::static_modint_base, T>;
        
        template <class T>
        using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;
        
        template <class> struct is_dynamic_modint : public std::false_type {};
        template <int id>
        struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};
        
        template <class T>
        using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;
        
    }  // namespace internal
    
}  // namespace atcoder

using mint=atcoder::modint1000000007;

mint dp[21][MAX][MAX][2];
vector<int> G[MAX];
int to[MAX][MAX],cn[MAX][MAX];

const int D=21;

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,M,K;cin>>N>>M>>K;
        if(N==0) break;
        
        for(int i=0;i<MAX;i++) G[i].clear();
        memset(dp,0,sizeof(dp));
        memset(to,-1,sizeof(to));
        memset(cn,0,sizeof(cn));
        
        vector<pair<string,string>> S(N);
        vector<string> use={""};
        for(int i=0;i<N;i++){
            cin>>S[i].fi>>S[i].se;
            use.push_back(S[i].fi);
            use.push_back(S[i].se);
        }
        sort(all(use));
        use.erase(unique(all(use)),use.end());
        
        for(int i=0;i<N;i++){
            G[lower_bound(all(use),S[i].fi)-use.begin()].push_back(lower_bound(all(use),S[i].se)-use.begin());
        }
        for(int i=1;i<si(use);i++){
            G[0].push_back(i);
        }
        
        vector<string> match;
        vector<string> T(K);
        for(int i=0;i<K;i++){
            cin>>T[i];
            for(int j=0;j<=si(T[i]);j++){
                match.push_back(T[i].substr(0,j));
            }
        }
        sort(all(match));
        match.erase(unique(all(match)),match.end());
        
        vector<pair<string,int>> X(si(match));
        for(int i=0;i<si(match);i++) X[i]=mp(match[i],i);
        sort(all(X),[](auto a,auto b){
            return si(a.fi)>si(b.fi);
        });
        
        for(int a=0;a<si(match);a++){
            for(int b=1;b<si(use);b++){
                string U=match[a]+use[b];
                for(int s=0;s<si(U);s++){
                    for(int i=0;i<K;i++){
                        int t=s+si(T[i]);
                        if(t>si(U)||t<=si(match[a])) continue;
                        if(U.substr(s,si(T[i]))==T[i]) cn[a][b]++;
                        if(cn[a][b]>=2) break;
                    }
                }
                for(auto x:X){
                    if(si(U)<si(x.fi)) continue;
                    if(U.substr(si(U)-si(x.fi))==x.fi){
                        to[a][b]=x.se;
                        break;
                    }
                }
            }
        }
        
        dp[0][0][0][0]=1;
        
        for(int i=0;i<M;i++){
            int s=i%D;
            for(int j=0;j<si(use);j++){
                for(int k=0;k<si(match);k++){
                    for(int f=0;f<2;f++){
                        if(dp[s][j][k][f]==0) continue;
                        
                        for(int t:G[j]){
                            if(f+cn[k][t]>=2) continue;
                            dp[(s+si(use[t]))%D][t][to[k][t]][f+cn[k][t]]+=dp[s][j][k][f];
                        }
                        
                        dp[s][j][k][f]=0;
                    }
                }
            }
        }
        
        mint ans=0;
        
        for(int j=0;j<si(use);j++){
            for(int k=0;k<si(match);k++){
                ans+=dp[M%D][j][k][1];
            }
        }
        
        cout<<ans.val()<<"\n";
    }
}
accuracy: 1
time_ms: 5690
memory_kb: 66484
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=605;
const ll INF=1LL<<62;

//modintのみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {
    
    namespace internal {
        
#ifndef _MSC_VER
        template <class T>
        using is_signed_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value ||
        std::is_same<T, __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int128 =
        typename std::conditional<std::is_same<T, __uint128_t>::value ||
        std::is_same<T, unsigned __int128>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using make_unsigned_int128 =
        typename std::conditional<std::is_same<T, __int128_t>::value,
        __uint128_t,
        unsigned __int128>;
        
        template <class T>
        using is_integral = typename std::conditional<std::is_integral<T>::value ||
        is_signed_int128<T>::value ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                         std::is_signed<T>::value) ||
        is_signed_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<(is_integral<T>::value &&
                                   std::is_unsigned<T>::value) ||
        is_unsigned_int128<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<
        is_signed_int128<T>::value,
        make_unsigned_int128<T>,
        typename std::conditional<std::is_signed<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type>::type;
        
#else
        
        template <class T> using is_integral = typename std::is_integral<T>;
        
        template <class T>
        using is_signed_int =
        typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using is_unsigned_int =
        typename std::conditional<is_integral<T>::value &&
        std::is_unsigned<T>::value,
        std::true_type,
        std::false_type>::type;
        
        template <class T>
        using to_unsigned = typename std::conditional<is_signed_int<T>::value,
        std::make_unsigned<T>,
        std::common_type<T>>::type;
        
#endif
        
        template <class T>
        using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
        
        template <class T>
        using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
        
        template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
        
    }  // namespace internal
    
}  // namespace atcoder

#include <utility>

namespace atcoder {
    
    namespace internal {
        
        constexpr long long safe_mod(long long x, long long m) {
            x %= m;
            if (x < 0) x += m;
            return x;
        }
        
        struct barrett {
            unsigned int _m;
            unsigned long long im;
            
            barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}
            
            unsigned int umod() const { return _m; }
            
            unsigned int mul(unsigned int a, unsigned int b) const {
                
                unsigned long long z = a;
                z *= b;
#ifdef _MSC_VER
                unsigned long long x;
                _umul128(z, im, &x);
#else
                unsigned long long x =
                (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
                unsigned int v = (unsigned int)(z - x * _m);
                if (_m <= v) v += _m;
                return v;
            }
        };
        
        constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
            if (m == 1) return 0;
            unsigned int _m = (unsigned int)(m);
            unsigned long long r = 1;
            unsigned long long y = safe_mod(x, m);
            while (n) {
                if (n & 1) r = (r * y) % _m;
                y = (y * y) % _m;
                n >>= 1;
            }
            return r;
        }
        
        constexpr bool is_prime_constexpr(int n) {
            if (n <= 1) return false;
            if (n == 2 || n == 7 || n == 61) return true;
            if (n % 2 == 0) return false;
            long long d = n - 1;
            while (d % 2 == 0) d /= 2;
            for (long long a : {2, 7, 61}) {
                long long t = d;
                long long y = pow_mod_constexpr(a, t, n);
                while (t != n - 1 && y != 1 && y != n - 1) {
                    y = y * y % n;
                    t <<= 1;
                }
                if (y != n - 1 && t % 2 == 0) {
                    return false;
                }
            }
            return true;
        }
        template <int n> constexpr bool is_prime = is_prime_constexpr(n);
        
        constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
            a = safe_mod(a, b);
            if (a == 0) return {b, 0};
            
            long long s = b, t = a;
            long long m0 = 0, m1 = 1;
            
            while (t) {
                long long u = s / t;
                s -= t * u;
                m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b
                
                
                auto tmp = s;
                s = t;
                t = tmp;
                tmp = m0;
                m0 = m1;
                m1 = tmp;
            }
            if (m0 < 0) m0 += b / s;
            return {s, m0};
        }
        
        constexpr int primitive_root_constexpr(int m) {
            if (m == 2) return 1;
            if (m == 167772161) return 3;
            if (m == 469762049) return 3;
            if (m == 754974721) return 11;
            if (m == 998244353) return 3;
            int divs[20] = {};
            divs[0] = 2;
            int cnt = 1;
            int x = (m - 1) / 2;
            while (x % 2 == 0) x /= 2;
            for (int i = 3; (long long)(i)*i <= x; i += 2) {
                if (x % i == 0) {
                    divs[cnt++] = i;
                    while (x % i == 0) {
                        x /= i;
                    }
                }
            }
            if (x > 1) {
                divs[cnt++] = x;
            }
            for (int g = 2;; g++) {
                bool ok = true;
                for (int i = 0; i < cnt; i++) {
                    if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                        ok = false;
                        break;
                    }
                }
                if (ok) return g;
            }
        }
        template <int m> constexpr int primitive_root = primitive_root_constexpr(m);
        
    }  // namespace internal
    
}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {
    
    namespace internal {
        
        struct modint_base {};
        struct static_modint_base : modint_base {};
        
        template <class T> using is_modint = std::is_base_of<modint_base, T>;
        template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;
        
    }  // namespace internal
    
    template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
    struct static_modint : internal::static_modint_base {
        using mint = static_modint;
        
    public:
        static constexpr int mod() { return m; }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        static_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        static_modint(T v) {
            long long x = (long long)(v % (long long)(umod()));
            if (x < 0) x += umod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        static_modint(T v) {
            _v = (unsigned int)(v % umod());
        }
        static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v -= rhs._v;
            if (_v >= umod()) _v += umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            unsigned long long z = _v;
            z *= rhs._v;
            _v = (unsigned int)(z % umod());
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            if (prime) {
                assert(_v);
                return pow(umod() - 2);
            } else {
                auto eg = internal::inv_gcd(_v, m);
                assert(eg.first == 1);
                return eg.second;
            }
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static constexpr unsigned int umod() { return m; }
        static constexpr bool prime = internal::is_prime<m>;
    };
    
    template <int id> struct dynamic_modint : internal::modint_base {
        using mint = dynamic_modint;
        
    public:
        static int mod() { return (int)(bt.umod()); }
        static void set_mod(int m) {
            assert(1 <= m);
            bt = internal::barrett(m);
        }
        static mint raw(int v) {
            mint x;
            x._v = v;
            return x;
        }
        
        dynamic_modint() : _v(0) {}
        template <class T, internal::is_signed_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            long long x = (long long)(v % (long long)(mod()));
            if (x < 0) x += mod();
            _v = (unsigned int)(x);
        }
        template <class T, internal::is_unsigned_int_t<T>* = nullptr>
        dynamic_modint(T v) {
            _v = (unsigned int)(v % mod());
        }
        dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }
        
        unsigned int val() const { return _v; }
        
        mint& operator++() {
            _v++;
            if (_v == umod()) _v = 0;
            return *this;
        }
        mint& operator--() {
            if (_v == 0) _v = umod();
            _v--;
            return *this;
        }
        mint operator++(int) {
            mint result = *this;
            ++*this;
            return result;
        }
        mint operator--(int) {
            mint result = *this;
            --*this;
            return result;
        }
        
        mint& operator+=(const mint& rhs) {
            _v += rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator-=(const mint& rhs) {
            _v += mod() - rhs._v;
            if (_v >= umod()) _v -= umod();
            return *this;
        }
        mint& operator*=(const mint& rhs) {
            _v = bt.mul(_v, rhs._v);
            return *this;
        }
        mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
        
        mint operator+() const { return *this; }
        mint operator-() const { return mint() - *this; }
        
        mint pow(long long n) const {
            assert(0 <= n);
            mint x = *this, r = 1;
            while (n) {
                if (n & 1) r *= x;
                x *= x;
                n >>= 1;
            }
            return r;
        }
        mint inv() const {
            auto eg = internal::inv_gcd(_v, mod());
            assert(eg.first == 1);
            return eg.second;
        }
        
        friend mint operator+(const mint& lhs, const mint& rhs) {
            return mint(lhs) += rhs;
        }
        friend mint operator-(const mint& lhs, const mint& rhs) {
            return mint(lhs) -= rhs;
        }
        friend mint operator*(const mint& lhs, const mint& rhs) {
            return mint(lhs) *= rhs;
        }
        friend mint operator/(const mint& lhs, const mint& rhs) {
            return mint(lhs) /= rhs;
        }
        friend bool operator==(const mint& lhs, const mint& rhs) {
            return lhs._v == rhs._v;
        }
        friend bool operator!=(const mint& lhs, const mint& rhs) {
            return lhs._v != rhs._v;
        }
        
    private:
        unsigned int _v;
        static internal::barrett bt;
        static unsigned int umod() { return bt.umod(); }
    };
    template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;
    
    using modint998244353 = static_modint<998244353>;
    using modint1000000007 = static_modint<1000000007>;
    using modint = dynamic_modint<-1>;
    
    namespace internal {
        
        template <class T>
        using is_static_modint = std::is_base_of<internal::static_modint_base, T>;
        
        template <class T>
        using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;
        
        template <class> struct is_dynamic_modint : public std::false_type {};
        template <int id>
        struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};
        
        template <class T>
        using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;
        
    }  // namespace internal
    
}  // namespace atcoder

using mint=atcoder::modint1000000007;

mint dp[21][MAX][MAX][2];
vector<int> G[MAX];
int to[MAX][MAX],cn[MAX][MAX];

const int D=21;

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,M,K;cin>>N>>M>>K;
        if(N==0) break;
        
        for(int i=0;i<MAX;i++) G[i].clear();
        memset(dp,0,sizeof(dp));
        memset(to,-1,sizeof(to));
        memset(cn,0,sizeof(cn));
        
        vector<pair<string,string>> S(N);
        vector<string> use={""};
        for(int i=0;i<N;i++){
            cin>>S[i].fi>>S[i].se;
            use.push_back(S[i].fi);
            use.push_back(S[i].se);
        }
        sort(all(use));
        use.erase(unique(all(use)),use.end());
        
        for(int i=0;i<N;i++){
            G[lower_bound(all(use),S[i].fi)-use.begin()].push_back(lower_bound(all(use),S[i].se)-use.begin());
        }
        for(int i=1;i<si(use);i++){
            G[0].push_back(i);
        }
        
        vector<string> match;
        vector<string> T(K);
        for(int i=0;i<K;i++){
            cin>>T[i];
            for(int j=0;j<=si(T[i]);j++){
                match.push_back(T[i].substr(0,j));
            }
        }
        sort(all(match));
        match.erase(unique(all(match)),match.end());
        
        vector<pair<string,int>> X(si(match));
        for(int i=0;i<si(match);i++) X[i]=mp(match[i],i);
        sort(all(X),[](auto a,auto b){
            return si(a.fi)>si(b.fi);
        });
        
        for(int a=0;a<si(match);a++){
            for(int b=1;b<si(use);b++){
                string U=match[a]+use[b];
                for(int s=0;s<si(U);s++){
                    for(int i=0;i<K;i++){
                        int t=s+si(T[i]);
                        if(t>si(U)||t<=si(match[a])) continue;
                        if(U.substr(s,si(T[i]))==T[i]) cn[a][b]++;
                    }
                }
                for(auto x:X){
                    if(si(U)<si(x.fi)) continue;
                    if(U.substr(si(U)-si(x.fi))==x.fi){
                        to[a][b]=x.se;
                        break;
                    }
                }
            }
        }
        
        dp[0][0][0][0]=1;
        
        for(int i=0;i<M;i++){
            int s=i%D;
            for(int j=0;j<si(use);j++){
                for(int k=0;k<si(match);k++){
                    for(int f=0;f<2;f++){
                        if(dp[s][j][k][f]==0) continue;
                        
                        for(int t:G[j]){
                            if(f+cn[k][t]>=2) continue;
                            dp[(s+si(use[t]))%D][t][to[k][t]][f+cn[k][t]]+=dp[s][j][k][f];
                        }
                        
                        dp[s][j][k][f]=0;
                    }
                }
            }
        }
        
        mint ans=0;
        
        for(int j=0;j<si(use);j++){
            for(int k=0;k<si(match);k++){
                ans+=dp[M%D][j][k][1];
            }
        }
        
        cout<<ans.val()<<"\n";
    }
}
accuracy: 1
time_ms: 5700
memory_kb: 66440
final_rank: 13

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define eps 1e-9
#define INF 2000000000              // 2e9
#define LLINF 2000000000000000000ll // 2e18 (llmax:9e18)
#define all(x) (x).begin(), (x).end()
#define sq(x) ((x) * (x))

#define rep(i, x) for (int i = 0; i < (int)(x); i++)
#define drep(i, x) for (int i = ((int)(x)-1); i >= 0; i--)

#define popcount __builtin_popcount
#define next __next
#define prev __prev

#ifndef LOCAL
#define dmp(...) ;
#else
#define dmp(...)                                                               \
  cerr << "[ " << #__VA_ARGS__ << " ] : " << dump_str(__VA_ARGS__) << endl
#endif

// ---------------- Utility ------------------

template <class T>
bool chmin(T &a, const T &b) {
  if (a <= b) return false;
  a = b;
  return true;
}

template <class T>
bool chmax(T &a, const T &b) {
  if (a >= b) return false;
  a = b;
  return true;
}

template <class T>
using MaxHeap = priority_queue<T>;

template <class T>
using MinHeap = priority_queue<T, vector<T>, greater<T>>;

template <class T>
vector<T> vect(int len, T elem) {
  return vector<T>(len, elem);
}

// ----------------- Input -------------------

template <class T, class U>
istream &operator>>(istream &is, pair<T, U> &p) {
  return is >> p.first >> p.second;
}

template <class T>
istream &operator>>(istream &is, vector<T> &vec) {
  for (int i = 0; i < vec.size(); i++) is >> vec[i];
  return is;
}

// ----------------- Output ------------------

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << p.first << ',' << p.second;
}

template <class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  for (const T &e : v) os << e << " ";
  return os;
}

template <class T>
ostream &operator<<(ostream &os, const deque<T> &d) {
  for (const T &e : d) os << e << " ";
  return os;
}

template <class T>
ostream &operator<<(ostream &os, const set<T> &s) {
  os << "{ ";
  for (const T &e : s) os << e << " ";
  return os << "}";
}

template <class T, class U>
ostream &operator<<(ostream &os, const map<T, U> &m) {
  os << "{ ";
  for (const auto &[key, val] : m) os << "( " << key << " -> " << val << " ) ";
  return os << "}";
}

template <class TupleTy, size_t... I>
void dump_tuple(ostream &os, const TupleTy t, std::index_sequence<I...>) {
  (..., (os << (I == 0 ? "" : ",") << std::get<I>(t)));
}

template <class... Args>
ostream &operator<<(ostream &os, const tuple<Args...> &t) {
  os << "(";
  dump_tuple(os, t, std::make_index_sequence<sizeof...(Args)>());
  return os << ")";
}

void dump_str_rec(ostringstream &) {}

template <class Head, class... Tail>
void dump_str_rec(ostringstream &oss, Head &&head, Tail &&... tail) {
  oss << ", " << head;
  dump_str_rec(oss, forward<Tail>(tail)...);
}

template <class T, class... U>
string dump_str(T &&arg, U &&... args) {
  ostringstream oss;
  oss << arg;
  dump_str_rec(oss, forward<U>(args)...);
  return oss.str();
}

// --------------- Fast I/O ------------------

void fastio() {
  cin.tie(0);
  ios::sync_with_stdio(0);
  cout << fixed << setprecision(20);
}

// ------------------ ACL --------------------


#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

// constexpr int MOD = 998244353;
constexpr int MOD = 1000000007;
using mint = atcoder::static_modint<MOD>;
ostream &operator<<(ostream &os, const mint &v) {
  return os << v.val();
}

// ------------ End of template --------------

#define endl "\n"
using ll = long long;
using pii = pair<int, int>;

const bool multitest = false;

struct AhoCorasick {
  const static int alphabet_size = 26;
  const int root = 0;
  const char base = 'a';

  AhoCorasick() : T(1) {}
  AhoCorasick(const vector<string> &ss) : T(1) {
    for (const string &s : ss) add_string(s);
    build();
  }

  struct Node {
    vector<int> child; // children of this node in Trie
    bool leaf;
    int par;         // parent
    char par_c;      // character on the edge from parent to this node
    int suf_link;    // suffix link
    int exit_link;   // exit link : direct suffix link to the nearest match
    int num_leaf;    //
    vector<int> go;  // transition of the automaton
    int match_count; // the number of matches of this state
    Node(int par = -1, char par_c = '$')
        : leaf(false), par(par), par_c(par_c), suf_link(-1), exit_link(-1),
          num_leaf(-1), match_count(-1) {
      child.assign(alphabet_size, -1);
      go.assign(alphabet_size, -1);
    }
  };

  vector<Node> T;

  int add_string(const string &s) {
    int v = root;
    for (char ch : s) {
      int c = ch - base;
      if (T[v].child[c] == -1) {
        T[v].child[c] = T.size();
        T.emplace_back(v, ch);
      }
      v = T[v].child[c];
    }
    T[v].leaf = true;
    return v;
  }

  int get_num_state() const { return T.size(); }

  int suf_link(int v) {
    if (T[v].suf_link == -1) {
      if (v == root || T[v].par == root) {
        T[v].suf_link = root;
      } else {
        int par_suf_link = suf_link(T[v].par);
        T[v].suf_link = go(par_suf_link, T[v].par_c);
      }
    }
    return T[v].suf_link;
  }

  int go(int v, char ch) {
    int c = ch - base;
    if (T[v].go[c] == -1) {
      if (T[v].child[c] != -1)
        T[v].go[c] = T[v].child[c];
      else
        T[v].go[c] = (v == root) ? root : go(suf_link(v), ch);
    }
    return T[v].go[c];
  }

  int match_count(int v) {
    if (T[v].match_count == -1) {
      if (v == root)
        T[v].match_count = 0;
      else {
        T[v].match_count = match_count(suf_link(v)) + (T[v].leaf ? 1 : 0);
      }
    }
    return T[v].match_count;
  }

  int exit_link(int v) {
    if (T[v].exit_link == -1) {
      if (v == root)
        T[v].exit_link = 0;
      else {
        int suf = suf_link(v);
        T[v].exit_link = T[suf].leaf ? suf : exit_link(suf);
      }
    }
    return T[v].exit_link;
  }

  int num_leaf(int v) {
    if (T[v].num_leaf == -1) {
      if (exit_link(v) == 0) {
        T[v].num_leaf = 0;
      } else {
        T[v].num_leaf = num_leaf(exit_link(v));
      }
      if (T[v].leaf) T[v].num_leaf++;
    }
    return T[v].num_leaf;
  }

  void build() {
    for (int v = 0; v < T.size(); v++) {
      suf_link(v);
      match_count(v);
      exit_link(v);
      num_leaf(v);
      for (int i = 0; i < alphabet_size; i++) go(v, base + i);
    }
  }

  Node &operator[](int v) { return T[v]; }
  int size() const { return T.size(); }
};

// 文字数、acの頂点、最後のword、季語の個数
// auto dp = vect(L, vect(S, vect(W, vect(2, mint(0)))));
mint dp[22][601][501][2];

bool solve() {
  int N, M, K;
  cin >> N >> M >> K;

  if ((N | M | K) == 0) return false;

  vector<string> zip;
  vector<string> a(N), b(N);
  for (int i = 0; i < N; i++) {
    cin >> a[i] >> b[i];
    zip.push_back(a[i]);
    zip.push_back(b[i]);
  }
  sort(all(zip));
  zip.erase(unique(all(zip)), zip.end());

  vector<vector<int>> g(zip.size());
  for (int i = 0; i < N; i++) {
    int u = lower_bound(all(zip), a[i]) - zip.begin();
    int v = lower_bound(all(zip), b[i]) - zip.begin();
    g[u].push_back(v);
  }

  vector<string> sw(K);
  for (int i = 0; i < K; i++) { cin >> sw[i]; }

  AhoCorasick ac(sw);

  int W = zip.size();
  int S = ac.get_num_state();

  auto go = [&](int v, int w) {
    int num_leaf = 0;
    for (char c : zip[w]) {
      v = ac.go(v, c);
      num_leaf += ac.num_leaf(v);
    }
    return make_pair(v, num_leaf);
  };

  const int L = 22;

  assert(S <= 600 && W <= 500);
  for (int i = 0; i < L; i++) {
    for (int j = 0; j < S; j++) {
      for (int k = 0; k < W; k++) {
        for (int l = 0; l < 2; l++) { dp[i][j][k][l] = mint(0); }
      }
    }
  }

  for (int i = 0; i < W; i++) {
    auto [v, num_leaf] = go(0, i);
    if (zip[i].size() > M) continue;
    if (num_leaf > 1) continue;
    dp[zip[i].size()][v][i][num_leaf] = mint(1);
  }

  for (int i = 0; i < M; i++) {
    for (int j = 0; j < S; j++) {
      for (int k = 0; k < W; k++) {
        for (int l = 0; l < 2; l++) {
          if (dp[i % L][j][k][l].val() == 0) continue;
          for (int u : g[k]) {
            if (i + zip[u].size() > M) continue;
            auto [v, num_leaf] = go(j, u);
            if (l + num_leaf > 1) continue;
            dp[(i + zip[u].size()) % L][v][u][l + num_leaf] +=
                dp[i % L][j][k][l];
          }
        }
      }
    }
    for (int j = 0; j < S; j++) {
      for (int k = 0; k < W; k++) {
        for (int l = 0; l < 2; l++) { dp[(i + L - 1) % L][j][k][l] = mint(0); }
      }
    }
  }

  mint ans(0);
  for (int j = 0; j < S; j++) {
    for (int k = 0; k < W; k++) { ans += dp[M % L][j][k][1]; }
  }

  cout << ans << endl;

  return true;
}

int main() {
  fastio();
  if (!multitest) {
    while (solve()) {}
  } else {
    cerr << "[Warning] Multi testcase mode on" << endl;
    int t;
    cin >> t;
    while (t--) solve();
  }
  return 0;
}
accuracy: 1
time_ms: 1740
memory_kb: 55360
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

template <uint64_t Modulus> class modint {
    using i64 = int64_t;
    using u32 = uint32_t;
    using u64 = uint64_t;

    static_assert(Modulus < static_cast<uint32_t>(1) << 31, "Modulus must be less than 2**31");
    static constexpr u32 mod = Modulus;
    u32 v;

public:
    constexpr modint(const i64 x = 0) noexcept : v(x < 0 ? mod - 1 - (-(x + 1) % mod) : x % mod) {}
    constexpr u32& val() noexcept { return v; }
    constexpr const u32& val() const noexcept { return v; }
    constexpr modint operator+(const modint& rhs) const noexcept { return modint(*this) += rhs; }
    constexpr modint operator-(const modint& rhs) const noexcept { return modint(*this) -= rhs; }
    constexpr modint operator*(const modint& rhs) const noexcept { return modint(*this) *= rhs; }
    constexpr modint operator/(const modint& rhs) const noexcept { return modint(*this) /= rhs; }
    constexpr modint& operator+=(const modint& rhs) noexcept {
        v += rhs.v;
        if (v >= mod) v -= mod;
        return *this;
    }
    constexpr modint& operator-=(const modint& rhs) noexcept {
        if (v < rhs.v) v += mod;
        v -= rhs.v;
        return *this;
    }
    constexpr modint& operator*=(const modint& rhs) noexcept {
        v = (u64)v * rhs.v % mod;
        return *this;
    }
    constexpr modint& operator/=(const modint& rhs) noexcept { return *this *= rhs.inv(); }
    constexpr modint pow(long long n) const noexcept {
        assert(0 <= n);
        modint self(*this), res(1);
        while (n > 0) {
            if (n & 1) res *= self;
            self *= self;
            n >>= 1;
        }
        return res;
    }
    constexpr modint inv() const noexcept {
        assert(*this != 0);
        return pow(mod - 2);
    }
    constexpr modint& operator++() noexcept {
        if (++v == mod) v = 0;
        return *this;
    }
    constexpr modint& operator--() noexcept {
        if (v == 0) v = mod;
        return --v, *this;
    }
    constexpr modint operator++(int) noexcept {
        modint t = *this;
        return ++*this, t;
    }
    constexpr modint operator--(int) noexcept {
        modint t = *this;
        return --*this, t;
    }
    constexpr modint operator-() const noexcept { return modint(mod - v); }
    template <class T> friend constexpr modint operator+(T x, modint y) noexcept { return modint(x) + y; }
    template <class T> friend constexpr modint operator-(T x, modint y) noexcept { return modint(x) - y; }
    template <class T> friend constexpr modint operator*(T x, modint y) noexcept { return modint(x) * y; }
    template <class T> friend constexpr modint operator/(T x, modint y) noexcept { return modint(x) / y; }
    constexpr bool operator==(const modint& rhs) const noexcept { return v == rhs.v; }
    constexpr bool operator!=(const modint& rhs) const noexcept { return v != rhs.v; }
    constexpr bool operator!() const noexcept { return !v; }
    friend std::istream& operator>>(std::istream& s, modint& rhs) noexcept {
        i64 v;
        rhs = modint{(s >> v, v)};
        return s;
    }
    friend std::ostream& operator<<(std::ostream& s, const modint& rhs) noexcept { return s << rhs.v; }
};

/**
 * @brief modint
 * @docs docs/modulo/modint.md
 */

template <size_t char_size, char margin = 'a'> struct Trie {
    struct Node {
        std::array<int, char_size> nxt;
        std::vector<int> idxs;
        int idx, sub;
        char key;
        Node(char c) : idx(-1), key(c) { fill(nxt.begin(), nxt.end(), -1); }
    };

    std::vector<Node> nodes;

    inline int& next(int i, int j) { return nodes[i].nxt[j]; }

    Trie() { nodes.emplace_back('$'); }

    void add(const std::string& s, int x = 0) {
        int cur = 0;
        for (const char& c : s) {
            int k = c - margin;
            if (next(cur, k) < 0) {
                next(cur, k) = nodes.size();
                nodes.emplace_back(c);
            }
            cur = next(cur, k);
            nodes[cur].sub++;
        }
        nodes[cur].idx = x;
        nodes[cur].idxs.emplace_back(x);
    }

    int find(const std::string& s) {
        int cur = 0;
        for (const char& c : s) {
            int k = c - margin;
            if (next(cur, k) < 0) return -1;
            cur = next(cur, k);
        }
        return cur;
    }

    int move(int pos, char c) {
        assert(pos < (int)nodes.size());
        return pos < 0 ? -1 : next(pos, c - margin);
    }

    int size() const { return nodes.size(); }

    int idx(int pos) { return pos < 0 ? -1 : nodes[pos].idx; }

    std::vector<int> idxs(int pos) { return pos < 0 ? std::vector<int>() : nodes[pos].idxs; }
};

/**
 * @brief Trie
 * @docs docs/string/Trie.md
 */

template <size_t char_size, char margin = 'a'> struct AhoCorasick : Trie<char_size + 1, margin> {
    void build(bool heavy = true) {
        int n = nodes.size();
        cnt.resize(n);
        for (int i = 0; i < n; i++) cnt[i] = nodes[i].idxs.size();
        std::queue<int> que;
        for (size_t i = 0; i <= char_size; i++) {
            if (~next(0, i)) {
                next(next(0, i), FAIL) = 0;
                que.emplace(next(0, i));
            } else
                next(0, i) = 0;
        }
        while (!que.empty()) {
            auto& cur = nodes[que.front()];
            int fail = cur.nxt[FAIL];
            cnt[que.front()] += cnt[fail];
            que.pop();
            for (size_t i = 0; i < char_size; i++) {
                int& nxt = cur.nxt[i];
                if (nxt < 0) {
                    nxt = next(fail, i);
                    continue;
                }
                next(nxt, FAIL) = next(fail, i);
                if (heavy) {
                    auto& u = nodes[nxt].idxs;
                    auto& v = nodes[next(fail, i)].idxs;
                    std::vector<int> w;
                    set_union(u.begin(), u.end(), v.begin(), v.end(), back_inserter(w));
                    u = w;
                }
                que.emplace(nxt);
            }
        }
    }

    long long match(const std::string& s) {
        long long res = 0;
        int cur = 0;
        for (const char& c : s) {
            cur = next(cur, c - margin);
            res += cnt[cur];
        }
        return res;
    }

    std::map<int, int> frequency(const std::string& s) {
        std::map<int, int> res;
        int cur = 0;
        for (const char& c : s) {
            cur = next(cur, c - margin);
            for (auto& idx : nodes[cur].idxs) res[idx]++;
        }
        return res;
    }

    int count(int pos) { return cnt[pos]; }

private:
    using super = Trie<char_size + 1, margin>;
    using super::next;
    using super::nodes;

    const int FAIL = char_size;
    std::vector<int> cnt;
};

/**
 * @brief Aho Corasick
 * @docs docs/string/AhoCorasick.md
 */

const long long MOD = 1000000007;

using mint = modint<MOD>;
const int MAX_N = 256, MAX_M = 512, MAX_K = 32, MAX_L = 20;
mint dp[MAX_L][MAX_K * MAX_L][MAX_N * 2][2], ndp[MAX_L][MAX_K * MAX_L][MAX_N * 2][2];

bool solve() {
    int N, M, K;
    cin >> N >> M >> K;
    if (N == 0 and M == 0 and K == 0) return false;
    vector<string> from(N), to(N), seasonword(K);
    for (int i = 0; i < N; i++) cin >> from[i] >> to[i];
    for (int i = 0; i < K; i++) cin >> seasonword[i];

    vector<string> S;
    for (auto& s : from) S.emplace_back(s);
    for (auto& s : to) S.emplace_back(s);
    sort(S.begin(), S.end());
    S.erase(unique(S.begin(), S.end()), S.end());
    map<string, int> mp;
    int m = S.size();
    for (int i = 0; i < m; i++) mp[S[i]] = i;
    vector<vector<int>> G(m);
    for (int i = 0; i < N; i++) G[mp[from[i]]].emplace_back(mp[to[i]]);

    AhoCorasick<26> AC;
    for (auto& s : seasonword) AC.add(s);
    AC.build(false);
    int n = AC.size();

    vector<vector<pair<int, int>>> nxt(n, vector<pair<int, int>>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            int cur = i, sum = 0;
            for (char& c : S[j]) {
                cur = AC.move(cur, c);
                sum += AC.count(cur);
            }
            nxt[i][j] = {cur, sum};
        }
    }

    for (int i = 0; i < MAX_L; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < m; k++) {
                for (int l = 0; l < 2; l++) {
                    dp[i][j][k][l] = ndp[i][j][k][l] = 0;
                }
            }
        }
    }
    dp[0][0][0][0] = 1;

    int cur = 0;
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < m; k++) {
                for (int l = 0; l < 2; l++) {
                    mint& val = dp[cur][j][k][l];
                    if (val == 0) continue;
                    if (i == 0) {
                        for (int nk = 0; nk < m; nk++) {
                            int ni = cur + int(S[nk].size()), nj = nxt[j][nk].first, nl = l + nxt[j][nk].second;
                            if (nl > 1) continue;
                            if (ni < MAX_L)
                                dp[ni][nj][nk][nl] += val;
                            else
                                ndp[ni - MAX_L][nj][nk][nl] += val;
                        }
                    } else {
                        for (int nk : G[k]) {
                            int ni = cur + int(S[nk].size()), nj = nxt[j][nk].first, nl = l + nxt[j][nk].second;
                            if (nl > 1) continue;
                            if (ni < MAX_L)
                                dp[ni][nj][nk][nl] += val;
                            else
                                ndp[ni - MAX_L][nj][nk][nl] += val;
                        }
                    }
                    val = 0;
                }
            }
        }
        if (++cur == MAX_L) {
            swap(dp, ndp);
            cur = 0;
        }
    }

    mint ans = 0;
    for (int j = 0; j < n; j++) {
        for (int k = 0; k < m; k++) {
            ans += dp[cur][j][k][1];
        }
    }
    cout << ans << '\n';
    return true;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    while (solve())
        ;
    return 0;
}
accuracy: 1
time_ms: 3420
memory_kb: 107992
final_rank: 8

code_snippet: #define LOCAL
#include <bits/stdc++.h>
using namespace std;
#pragma region Macros
typedef long long ll;
typedef __int128_t i128;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ALL(x) (x).begin(), (x).end()

template <typename T> istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v) is >> x;
    return is;
}
template <typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
    for (size_t i = 0; i < v.size(); i++) {
        os << v[i] << (i + 1 == v.size() ? "" : " ");
    }
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const unordered_map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const unordered_set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const deque<T>& v) {
    for (size_t i = 0; i < v.size(); i++) {
        os << v[i] << (i + 1 == v.size() ? "" : " ");
    }
    return os;
}
template <typename T, size_t N> ostream& operator<<(ostream& os, const array<T, N>& v) {
    for (size_t i = 0; i < N; i++) {
        os << v[i] << (i + 1 == N ? "" : " ");
    }
    return os;
}

template <int i, typename T> void print_tuple(ostream&, const T&) {}
template <int i, typename T, typename H, class... Args> void print_tuple(ostream& os, const T& t) {
    if (i) os << ',';
    os << get<i>(t);
    print_tuple<i + 1, T, Args...>(os, t);
}
template <typename... Args> ostream& operator<<(ostream& os, const tuple<Args...>& t) {
    os << '{';
    print_tuple<0, tuple<Args...>, Args...>(os, t);
    return os << '}';
}

void debug_out() { cerr << '\n'; }
template <class Head, class... Tail> void debug_out(Head&& head, Tail&&... tail) {
    cerr << head;
    if (sizeof...(Tail) > 0) cerr << ", ";
    debug_out(move(tail)...);
}
#ifdef LOCAL
#define debug(...)                                                                   \
    cerr << " ";                                                                     \
    cerr << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << '\n'; \
    cerr << " ";                                                                     \
    debug_out(__VA_ARGS__)
#else
#define debug(...) void(0)
#endif

template <typename T> T gcd(T x, T y) { return y != 0 ? gcd(y, x % y) : x; }
template <typename T> T lcm(T x, T y) { return x / gcd(x, y) * y; }

int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(long long t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int botbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int botbit(long long a) { return a == 0 ? 64 : __builtin_ctzll(a); }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(long long t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }
long long MSK(int n) { return (1LL << n) - 1; }

template <class T> T ceil(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <class T> T floor(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? x / y : (x - y + 1) / y);
}

template <class T1, class T2> inline bool chmin(T1& a, T2 b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T1, class T2> inline bool chmax(T1& a, T2 b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <typename T> void mkuni(vector<T>& v) {
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
}
template <typename T> int lwb(const vector<T>& v, const T& x) { return lower_bound(v.begin(), v.end(), x) - v.begin(); }
#pragma endregion

#include <cassert>
#include <cstdint>
#include <iostream>

template <uint64_t Modulus> class modint {
    using i64 = int64_t;
    using u32 = uint32_t;
    using u64 = uint64_t;

    static_assert(Modulus < static_cast<uint32_t>(1) << 31, "Modulus must be less than 2**31");
    static constexpr u32 mod = Modulus;
    u32 v;

public:
    constexpr modint(const i64 x = 0) noexcept : v(x < 0 ? mod - 1 - (-(x + 1) % mod) : x % mod) {}
    constexpr u32& val() noexcept { return v; }
    constexpr const u32& val() const noexcept { return v; }
    constexpr modint operator+(const modint& rhs) const noexcept { return modint(*this) += rhs; }
    constexpr modint operator-(const modint& rhs) const noexcept { return modint(*this) -= rhs; }
    constexpr modint operator*(const modint& rhs) const noexcept { return modint(*this) *= rhs; }
    constexpr modint operator/(const modint& rhs) const noexcept { return modint(*this) /= rhs; }
    constexpr modint& operator+=(const modint& rhs) noexcept {
        v += rhs.v;
        if (v >= mod) v -= mod;
        return *this;
    }
    constexpr modint& operator-=(const modint& rhs) noexcept {
        if (v < rhs.v) v += mod;
        v -= rhs.v;
        return *this;
    }
    constexpr modint& operator*=(const modint& rhs) noexcept {
        v = (u64)v * rhs.v % mod;
        return *this;
    }
    constexpr modint& operator/=(const modint& rhs) noexcept { return *this *= rhs.inv(); }
    constexpr modint pow(long long n) const noexcept {
        assert(0 <= n);
        modint self(*this), res(1);
        while (n > 0) {
            if (n & 1) res *= self;
            self *= self;
            n >>= 1;
        }
        return res;
    }
    constexpr modint inv() const noexcept {
        assert(*this != 0);
        return pow(mod - 2);
    }
    constexpr modint& operator++() noexcept {
        if (++v == mod) v = 0;
        return *this;
    }
    constexpr modint& operator--() noexcept {
        if (v == 0) v = mod;
        return --v, *this;
    }
    constexpr modint operator++(int) noexcept {
        modint t = *this;
        return ++*this, t;
    }
    constexpr modint operator--(int) noexcept {
        modint t = *this;
        return --*this, t;
    }
    constexpr modint operator-() const noexcept { return modint(mod - v); }
    template <class T> friend constexpr modint operator+(T x, modint y) noexcept { return modint(x) + y; }
    template <class T> friend constexpr modint operator-(T x, modint y) noexcept { return modint(x) - y; }
    template <class T> friend constexpr modint operator*(T x, modint y) noexcept { return modint(x) * y; }
    template <class T> friend constexpr modint operator/(T x, modint y) noexcept { return modint(x) / y; }
    constexpr bool operator==(const modint& rhs) const noexcept { return v == rhs.v; }
    constexpr bool operator!=(const modint& rhs) const noexcept { return v != rhs.v; }
    constexpr bool operator!() const noexcept { return !v; }
    friend std::istream& operator>>(std::istream& s, modint& rhs) noexcept {
        i64 v;
        rhs = modint{(s >> v, v)};
        return s;
    }
    friend std::ostream& operator<<(std::ostream& s, const modint& rhs) noexcept { return s << rhs.v; }
};

/**
 * @brief modint
 * @docs docs/modulo/modint.md
 */

#include <array>
#include <cassert>
#include <string>
#include <vector>

template <size_t char_size, char margin = 'a'> struct Trie {
    struct Node {
        std::array<int, char_size> nxt;
        std::vector<int> idxs;
        int idx, sub;
        char key;
        Node(char c) : idx(-1), key(c) { fill(nxt.begin(), nxt.end(), -1); }
    };

    std::vector<Node> nodes;

    inline int& next(int i, int j) { return nodes[i].nxt[j]; }

    Trie() { nodes.emplace_back('$'); }

    void add(const std::string& s, int x = 0) {
        int cur = 0;
        for (const char& c : s) {
            int k = c - margin;
            if (next(cur, k) < 0) {
                next(cur, k) = nodes.size();
                nodes.emplace_back(c);
            }
            cur = next(cur, k);
            nodes[cur].sub++;
        }
        nodes[cur].idx = x;
        nodes[cur].idxs.emplace_back(x);
    }

    int find(const std::string& s) {
        int cur = 0;
        for (const char& c : s) {
            int k = c - margin;
            if (next(cur, k) < 0) return -1;
            cur = next(cur, k);
        }
        return cur;
    }

    int move(int pos, char c) {
        assert(pos < (int)nodes.size());
        return pos < 0 ? -1 : next(pos, c - margin);
    }

    int size() const { return nodes.size(); }

    int idx(int pos) { return pos < 0 ? -1 : nodes[pos].idx; }

    std::vector<int> idxs(int pos) { return pos < 0 ? std::vector<int>() : nodes[pos].idxs; }
};

/**
 * @brief Trie
 * @docs docs/string/Trie.md
 */

#include <map>
#include <queue>

template <size_t char_size, char margin = 'a'> struct AhoCorasick : Trie<char_size + 1, margin> {
    void build(bool heavy = true) {
        int n = nodes.size();
        cnt.resize(n);
        for (int i = 0; i < n; i++) cnt[i] = nodes[i].idxs.size();
        std::queue<int> que;
        for (size_t i = 0; i <= char_size; i++) {
            if (~next(0, i)) {
                next(next(0, i), FAIL) = 0;
                que.emplace(next(0, i));
            } else
                next(0, i) = 0;
        }
        while (!que.empty()) {
            auto& cur = nodes[que.front()];
            int fail = cur.nxt[FAIL];
            cnt[que.front()] += cnt[fail];
            que.pop();
            for (size_t i = 0; i < char_size; i++) {
                int& nxt = cur.nxt[i];
                if (nxt < 0) {
                    nxt = next(fail, i);
                    continue;
                }
                next(nxt, FAIL) = next(fail, i);
                if (heavy) {
                    auto& u = nodes[nxt].idxs;
                    auto& v = nodes[next(fail, i)].idxs;
                    std::vector<int> w;
                    set_union(u.begin(), u.end(), v.begin(), v.end(), back_inserter(w));
                    u = w;
                }
                que.emplace(nxt);
            }
        }
    }

    long long match(const std::string& s) {
        long long res = 0;
        int cur = 0;
        for (const char& c : s) {
            cur = next(cur, c - margin);
            res += cnt[cur];
        }
        return res;
    }

    std::map<int, int> frequency(const std::string& s) {
        std::map<int, int> res;
        int cur = 0;
        for (const char& c : s) {
            cur = next(cur, c - margin);
            for (auto& idx : nodes[cur].idxs) res[idx]++;
        }
        return res;
    }

    int count(int pos) { return cnt[pos]; }

private:
    using super = Trie<char_size + 1, margin>;
    using super::next;
    using super::nodes;

    const int FAIL = char_size;
    std::vector<int> cnt;
};

/**
 * @brief Aho Corasick
 * @docs docs/string/AhoCorasick.md
 */

const int INF = 1e9;
const long long IINF = 1e18;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const char dir[4] = {'D', 'R', 'U', 'L'};
const long long MOD = 1000000007;
// const long long MOD = 998244353;

using mint = modint<MOD>;
const int MAX_N = 256, MAX_M = 512, MAX_K = 32, MAX_L = 20;
mint dp[MAX_L][MAX_K * MAX_L][MAX_N * 2]
       [2],  // i 文字できていて現在の状態が j で直前に追加した単語が k で季語の個数が l
    ndp[MAX_L][MAX_K * MAX_L][MAX_N * 2][2];

bool solve() {
    int N, M, K;
    cin >> N >> M >> K;
    if (N == 0 and M == 0 and K == 0) return false;
    vector<string> from(N), to(N), seasonword(K);
    for (int i = 0; i < N; i++) cin >> from[i] >> to[i];
    for (int i = 0; i < K; i++) cin >> seasonword[i];

    vector<string> S;
    for (auto& s : from) S.emplace_back(s);
    for (auto& s : to) S.emplace_back(s);
    sort(S.begin(), S.end());
    S.erase(unique(S.begin(), S.end()), S.end());
    map<string, int> mp;
    int m = S.size();
    for (int i = 0; i < m; i++) mp[S[i]] = i;
    vector<vector<int>> G(m);
    for (int i = 0; i < N; i++) G[mp[from[i]]].emplace_back(mp[to[i]]);

    AhoCorasick<26> AC;
    for (auto& s : seasonword) AC.add(s);
    AC.build(false);
    int n = AC.size();

    vector<vector<pair<int, int>>> nxt(n, vector<pair<int, int>>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            int cur = i, sum = 0;
            for (char& c : S[j]) {
                cur = AC.move(cur, c);
                sum += AC.count(cur);
            }
            nxt[i][j] = {cur, sum};
        }
    }

    for (int i = 0; i < MAX_L; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < m; k++) {
                for (int l = 0; l < 2; l++) {
                    dp[i][j][k][l] = ndp[i][j][k][l] = 0;
                }
            }
        }
    }
    dp[0][0][0][0] = 1;

    int cur = 0;
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < m; k++) {
                for (int l = 0; l < 2; l++) {
                    mint& val = dp[cur][j][k][l];
                    if (val == 0) continue;
                    if (i == 0) {
                        for (int nk = 0; nk < m; nk++) {
                            int ni = cur + int(S[nk].size()), nj = nxt[j][nk].first, nl = l + nxt[j][nk].second;
                            if (nl > 1) continue;
                            if (ni < MAX_L)
                                dp[ni][nj][nk][nl] += val;
                            else
                                ndp[ni - MAX_L][nj][nk][nl] += val;
                        }
                    } else {
                        for (int nk : G[k]) {
                            int ni = cur + int(S[nk].size()), nj = nxt[j][nk].first, nl = l + nxt[j][nk].second;
                            if (nl > 1) continue;
                            if (ni < MAX_L)
                                dp[ni][nj][nk][nl] += val;
                            else
                                ndp[ni - MAX_L][nj][nk][nl] += val;
                        }
                    }
                    val = 0;
                }
            }
        }
        if (++cur == MAX_L) {
            swap(dp, ndp);
            cur = 0;
        }
    }

    mint ans = 0;
    for (int j = 0; j < n; j++) {
        for (int k = 0; k < m; k++) {
            ans += dp[cur][j][k][1];
        }
    }
    cout << ans << '\n';
    return true;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    while (solve())
        ;
    return 0;
}
accuracy: 1
time_ms: 3410
memory_kb: 108176
final_rank: 7

code_snippet: /*	author:  Kite_kuma
	created: 2021.11.01 20:06:53 */

// #ifdef LOCAL
// #define _GLIBCXX_DEBUG
// #endif
#include <bits/stdc++.h>
using namespace std;

#pragma region macros

#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define popcnt(n) __builtin_popcountll((long long)n)

#define REPname(a, b, c, d, e, ...) e
#define rep(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int Counter_in_rep_macro = 0; Counter_in_rep_macro < (x); ++Counter_in_rep_macro)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))

#define DREPname(a, b, c, d, e, ...) e
#define drep(...) DREPname(__VA_ARGS__, DREP3, DREP2, DREP1)(__VA_ARGS__)
#define DREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define DREP2(i, l, r) for(int i = (r)-1; i >= (l); --i)
#define DREP3(i, l, r, c) for(int i = (r)-1; i >= (l); i -= (c))

#pragma endregion

#pragma region aliases

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = std::vector<int>;
using vvi = std::vector<std::vector<int>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vll = std::vector<ll>;
using vvll = std::vector<vll>;
using vvvll = std::vector<vvll>;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;
template <class T = ll>
using V = std::vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
template <class T = ll>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T = ll>
using pqdn = std::priority_queue<T>;

#pragma endregion

#pragma region constants

const int inf = 1e9;
const long long INF = 1e18;
const long double pi = acos(-1);
const char dl = '\n';
const char sp = ' ';
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const int mod_1000000007 = 1000000007;
const int mod_998244353 = 998244353;

#pragma endregion

#pragma region basic_operation

template <class T0, class T1, class T2>
inline bool in_range(T0 x, T1 lef, T2 rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool f = 1) { std::cout << (f ? "Yes" : "No") << '\n'; }
void No() { std::cout << "No\n"; }
void YES(bool f = 1) { std::cout << (f ? "YES" : "NO") << '\n'; }
void NO() { std::cout << "NO\n"; }

template <class T>
void drop(T answer) {
	std::cout << answer << '\n';
	exit(0);
}

void err(bool flag = true) {
	if(!flag) return;
	std::cout << -1 << '\n';
	exit(0);
}

template <class T>
void vout(std::vector<T> const &v, bool vertically = 0) {
	if(vertically) {
		for(auto const &a : v) {
			std::cout << a << '\n';
		}
		return;
	}
	for(auto it = v.begin(); it != v.end(); it++) {
		std::cout << (*it);
		if(it != v.end() - 1) {
			std::cout << ' ';
		}
	}
	std::cout << '\n';
	return;
}

inline void print() { std::cout << '\n'; }
template <class T>
inline void print(T x) {
	std::cout << x << '\n';
	return;
}
template <typename Head, typename... Tail>
void print(Head H, Tail... T) {
	std::cout << H << " ";
	print(T...);
}

template <class T>
void add(std::vector<T> &v, T val) {
	for(auto &a : v) a += val;
	return;
}

template <class T>
T dup(T a, T b) {
	assert(b != 0);
	return (a + b - 1) / b;
}

template <class T>
T greatest_lower_multiple(T x, T d) {
	if(d == 0) return 0;
	if(d < 0) d *= -1;
	T y = x % d;
	if(y < 0) y += d;
	return x - y;
}

template <class T>
T least_upper_multiple(T x, T d) {
	return -greatest_lower_multiple(-x, d);
}

long long POW(long long a, long long n) {
	long long res = 1;
	while(n > 0) {
		if(n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}

long long modpow(long long a, long long n, long long mod) {  // a^n mod
	assert(n >= 0 && mod);
	if(mod == 1) return 0LL;
	long long res = 1;
	a %= mod;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res < 0 ? res + mod : res;
}

// return x which satisfies a * x % mod == gcd(a, mod)
// not (mod | a)
long long modinv(long long a, long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		std::swap(a, b);
		u -= t * v;
		std::swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

template <class T>
int lb(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::lower_bound(a.begin(), a.end(), x));
}
template <class T>
int ub(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::upper_bound(a.begin(), a.end(), x));
}
template <class T>
void unq_sort(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<int> press(std::vector<T> &a) {
	auto vec = a;
	unq_sort(vec);
	std::vector<int> ret;
	for(auto &v : a) ret.push_back(lb(vec, v));
	return ret;
}

#pragma endregion

#pragma region input
#define VEC(type, name, size) \
	vector<type> name(size);  \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHR(...)      \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DBL(...)        \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define TPL3(type0, type1, type2, name)   \
	std::tuple<type0, type1, type2> name; \
	scanner::INPUT(name);
#define TPL4(type0, type1, type2, type3, name)   \
	std::tuple<type0, type1, type2, type3> name; \
	scanner::INPUT(name);

namespace scanner {
template <class T>
void scan(T &a) {
	std::cin >> a;
}

template <class T, class L>
void scan(std::pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}

template <class T0, class T1, class T2>
void scan(std::tuple<T0, T1, T2> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	scan(t0);
	scan(t1);
	scan(t2);
	p = std::make_tuple(t0, t1, t2);
}

template <class T0, class T1, class T2, class T3>
void scan(std::tuple<T0, T1, T2, T3> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	T3 t3;
	scan(t0);
	scan(t1);
	scan(t2);
	scan(t3);
	p = std::make_tuple(t0, t1, t2, t3);
}

template <class T>
void scan(std::vector<T> &a) {
	for(auto &i : a) scan(i);
}

void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &...tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner

template <typename T1, typename T2>
std::istream &operator>>(std::istream &is, std::pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}
#pragma endregion

#pragma region debug

#pragma region output
template <typename T1, typename T2>
std::ostream &std::operator<<(std::ostream &os, const std::pair<T1, T2> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <class T>
std::ostream &std::operator<<(std::ostream &os, const std::vector<T> &v) {
	for(int i = 0; i < (int)v.size(); i++) {
		if(i) os << " ";
		os << v[i];
	}
	return os;
}
#pragma endregion

#pragma region view

namespace viewer {
void view(const long long e) {
	if(e == INF)
		std::cerr << "INF";
	else if(e == -INF)
		std::cerr << "-INF";
	else
		std::cerr << e;
}

void view(const int e) {
	if(e == inf)
		std::cerr << "inf";
	else if(e == -inf)
		std::cerr << "-inf";
	else
		std::cerr << e;
}

template <typename T>
void view(const T e) {
	std::cerr << e;
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << "(";
	view(p.first);
	std::cerr << ", ";
	view(p.second);
	std::cerr << ")";
}

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ")";
}

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ", ";
	view(std::get<3>(p));
	std::cerr << ")";
}

template <typename T>
void view(const std::set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::unordered_set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<T> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(const auto &e : v) {
		view(e);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	std::cerr << "{\n";
	for(const auto &v : vv) {
		std::cerr << "\t";
		view(v);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	std::cerr << "{\n";
	for(const auto &c : v) {
		std::cerr << "\t(";
		view(c.first);
		std::cerr << ", ";
		view(c.second);
		std::cerr << ")\n";
	}
	std::cerr << "}";
}

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}
}  // namespace viewer

#pragma endregion

// when debugging : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	viewer::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "\b\b]\n";                                   \
	} while(0)
#define dump(x)                                      \
	do {                                             \
		std::cerr << __LINE__ << " " << #x << " : "; \
		viewer::view(x);                             \
		std::cerr << '\n';                           \
	} while(0)

#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

#pragma endregion

#pragma region Aho_Corasick
#pragma region Trie

template <int char_size>
struct TrieNode {
	int nxt[char_size];

	int exist;           // 子孫が何個あるか(このノードで終わりの文字列は除く)
	vector<int> accept;  // このノードで終わりの単語の番号を入れた配列(追加順)

	TrieNode() : exist(0) { memset(nxt, -1, sizeof(nxt)); }
};
template <int char_size = 26, int margin = 'a'> /* <26,'a'> など */
struct Trie {
	using Node = TrieNode<char_size>;

	vector<Node> nodes;
	int root;

	Trie() : root(0) { nodes.push_back(Node()); }

	void update_direct(int node, int id) { nodes[node].accept.push_back(id); }

	// nodeの重さ(要素数)1増大
	void update_child(int node, int child, int id) { ++nodes[node].exist; }

	void add(const string &str, int str_index, int node_index, int id) {
		if(str_index == str.size()) {
			update_direct(node_index, id);  // 単語の終わりを示す
		} else {
			const int c = str[str_index] - margin;
			if(nodes[node_index].nxt[c] == -1) {
				nodes[node_index].nxt[c] = (int)nodes.size();
				nodes.push_back(Node());
			}
			add(str, str_index + 1, nodes[node_index].nxt[c], id);
			update_child(node_index, nodes[node_index].nxt[c], id);
		}
	}

	void add(const string &str, int id) { add(str, 0, 0, id); }

	void add(const string &str) { add(str, nodes[0].exist); }

	void query(const string &str, const function<void(int)> &f, int str_index, int node_index) {
		for(auto &idx : nodes[node_index].accept) f(idx);
		if(str_index == str.size()) {
			return;
		} else {
			const int c = str[str_index] - margin;
			if(nodes[node_index].nxt[c] == -1) return;
			query(str, f, str_index + 1, nodes[node_index].nxt[c]);
		}
	}

	void query(const string &str, const function<void(int)> &f) { query(str, f, 0, 0); }

	int count() const { return (nodes[0].exist); }  // 単語数(重複含む)

	int size() const { return ((int)nodes.size()); }  // node数
};

#pragma endregion

template <int char_size, int margin>
struct AhoCorasick : Trie<char_size + 1, margin> {
	using Trie<char_size + 1, margin>::Trie;

	const int FAIL = char_size;
	vector<int> correct;

	void build(bool heavy = true) {
		correct.resize(this->size());
		for(int i = 0; i < this->size(); i++) {
			correct[i] = (int)this->nodes[i].accept.size();
		}
		queue<int> que;
		// determine nodes[i].nxt[FAIL] at first, and next determine nodes[i].nxt[0~25]
		for(int i = 0; i <= char_size; i++) {
			if(~this->nodes[0].nxt[i]) {  // this->nodes[0].nxt[i] != -1
				this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0;
				que.emplace(this->nodes[0].nxt[i]);
			} else {
				this->nodes[0].nxt[i] = 0;
			}
		}
		while(!que.empty()) {
			auto &now = this->nodes[que.front()];
			int fail = now.nxt[FAIL];
			correct[que.front()] += correct[fail];
			que.pop();
			for(int i = 0; i < char_size; i++) {
				if(~now.nxt[i]) {  // now.nxt[i] != -1
					this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i];
					if(heavy) {
						auto &u = this->nodes[now.nxt[i]].accept;
						auto &v = this->nodes[this->nodes[fail].nxt[i]].accept;
						vector<int> accept;
						set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));
						u = accept;
					}
					que.emplace(now.nxt[i]);
				} else {
					now.nxt[i] = this->nodes[fail].nxt[i];
				}
			}
		}
	}

	map<int, int> match(const string &str, int now = 0) {
		map<int, int> result;
		for(auto &c : str) {
			now = this->nodes[now].nxt[c - margin];
			for(auto &v : this->nodes[now].accept) result[v] += 1;
		}
		return result;
	}

	pair<int64_t, int> move(const char &c, int now = 0) {
		now = this->nodes[now].nxt[c - margin];
		return {correct[now], now};
	}

	// 一致要素数, 最終node
	pair<int64_t, int> move(const string &str, int now = 0) {
		int64_t sum = 0;
		for(auto &c : str) {
			auto nxt = move(c, now);
			sum += nxt.first;
			now = nxt.second;
		}
		return {sum, now};
	}
};
#pragma endregion

#pragma region modint

const int mod = mod_1000000007;

template <int mod>
struct ModInt {
	int x;
	ModInt() : x(0) {}
	ModInt(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
	ModInt &operator+=(const ModInt &p) {
		if((x += p.x) >= mod) x -= mod;
		return *this;
	}
	ModInt &operator-=(const ModInt &p) {
		if((x += mod - p.x) >= mod) x -= mod;
		return *this;
	}
	ModInt &operator*=(const ModInt &p) {
		x = (int)(1LL * x * p.x % mod);
		return *this;
	}
	ModInt &operator/=(const ModInt &p) {
		*this *= p.inverse();
		return *this;
	}
	ModInt operator-() const { return ModInt(-x); }
	ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
	ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
	ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
	ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
	bool operator==(const ModInt &p) const { return x == p.x; }
	bool operator!=(const ModInt &p) const { return x != p.x; }
	ModInt inverse() const {
		int a = x, b = mod, u = 1, v = 0, t;
		while(b > 0) {
			t = a / b;
			swap(a -= t * b, b);
			swap(u -= t * v, v);
		}
		return ModInt(u);
	}
	ModInt pow(long long n) const {
		ModInt ret(1), mul(x);
		while(n > 0) {
			if(n & 1) ret *= mul;
			mul *= mul;
			n >>= 1;
		}
		return ret;
	}
	friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; }
	friend istream &operator>>(istream &is, ModInt &a) {
		long long t;
		is >> t;
		a = ModInt<mod>(t);
		return (is);
	}
	static int get_mod() { return mod; }
};
using mint = ModInt<mod>;

#pragma endregion

mint solve(int n) {
	int m, k;
	cin >> m >> k;
	map<string, int> dict;
	V<pair<string, string>> con;
	rep(i, n) {
		string from, to;
		cin >> from >> to;
		con.emplace_back(from, to);
		dict[from] = 0;
		dict[to] = 0;
	}
	V<string> words;
	int sz_words = 0;
	foa(p, dict) { p.second = sz_words++; }
	words.resize(sz_words);
	foa(p, dict) { words[p.second] = p.first; }

	vvi g(sz_words);
	foa(t, con) {
		int from = dict[t.first];
		int to = dict[t.second];
		g[from].push_back(to);
	}

	V<string> seasonwords(k);
	AhoCorasick<26, 'a'> ac;
	foa(t, seasonwords) {
		cin >> t;
		ac.add(t);
	}
	ac.build();
	int nodes = ac.size();

	VV<pair<int, int>> arrow(nodes, V<pair<int, int>>(sz_words));
	// match, node_to

	rep(node_from, nodes) {
		int node_to, match;
		rep(i, sz_words) {
			tie(match, node_to) = ac.move(words[i], node_from);
			arrow[node_from][i] = make_pair(match, node_to);
		}
	}

	unordered_map<ll, mint> hash_dp;
	auto to_hash = [&](int i, int j, int k, int l) -> ll {
		return (ll)l + (ll)k * 700 + (ll)j * n * 2 * 700 + (ll)i * n * 2 * 700 * 2;
	};

	rep(i, sz_words) {
		string w = words[i];
		int is_season, node;
		if(int(w.size()) > m) continue;
		tie(is_season, node) = ac.move(w, 0);
		if(is_season < 2) hash_dp[to_hash(w.size(), is_season, i, node)] = 1;
	}

	rep(len, 1, m) {
		rep(is_seasoned, 2) rep(word_id, sz_words) rep(node, nodes) {
			ll h = to_hash(len, is_seasoned, word_id, node);
			if(!hash_dp.count(h)) continue;
			const mint &val = hash_dp[h];
			if(val == 0) continue;
			foa(nxtword_id, g[word_id]) {
				const string &nxt_str = words[nxtword_id];
				int len_nxt = len + nxt_str.size();
				if(len_nxt > m) continue;
				int season_ad, node_nxt;
				tie(season_ad, node_nxt) = arrow[node][nxtword_id];
				int nxt_season = is_seasoned + season_ad;
				if(nxt_season >= 2) continue;
				hash_dp[(to_hash(len_nxt, nxt_season, nxtword_id, node_nxt))] += val;
			}
		}
	}
	mint ans = 0;
	rep(i, sz_words) rep(j, nodes) {
		ans += hash_dp[(to_hash(m, 1, i, j))];
	}

	return ans;
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout << std::fixed << std::setprecision(15);
	srand((unsigned)time(NULL));

	int n;
	while(cin >> n && n) cout << solve(n) << dl;

	return 0;
}
accuracy: 1
time_ms: 5000
memory_kb: 131484
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll MOD = 1e9 + 7;
struct Mint {
    ll x;
    Mint(ll xx = 0) {
        x = ((xx % MOD) + MOD) % MOD;
    }
    Mint operator+(Mint b) { return Mint(x + b.x); }
    Mint operator-(Mint b) { return Mint(x - b.x); }
    Mint operator*(Mint b) { return Mint(x * b.x); }
    Mint operator/(Mint b) { return *this * b.inv(); }
    Mint& operator+=(Mint b) { return *this = *this + b; }
    Mint& operator-=(Mint b) { return *this = *this - b; }
    Mint& operator*=(Mint b) { return *this = *this * b; }
    Mint& operator/=(Mint b) { return *this = *this / b; }
    Mint pow(ll n) {
        Mint a = *this, ret = 1;
        while (n) {
            if (n & 1)
                ret = ret * a;
            a = a * a;
            n >>= 1;
        }
        return ret;
    }
    Mint inv() { return pow(MOD - 2); }
};

template <int char_size, int margin>
struct Trie {
    struct Node {
        int nxt[char_size];
        int exist;
        vector<int> accept;
        Node() : exist(0) {
            memset(nxt, -1, sizeof(nxt));
        }
    };
    vector<Node> nodes;
    int root;
    Trie() : root(0) {
        nodes.emplace_back();
    }
    void add(const string& s) {
        int x = nodes[0].exist, pos = 0;
        for (auto&& ch : s) {
            nodes[pos].exist++;
            int c = ch - margin;
            if (nodes[pos].nxt[c] == -1) {
                int npos = nodes.size();
                nodes[pos].nxt[c] = npos;
                nodes.emplace_back();
                pos = npos;
            } else
                pos = nodes[pos].nxt[c];
        }
        nodes[pos].accept.emplace_back(x);
    }
    int find(const string& s) {
        int pos = 0;
        for (auto&& ch : s) {
            int c = ch - margin;
            pos = nodes[pos].nxt[c];
            if (pos < 0)
                return -1;
        }
        return pos;
    }
    int move(char ch, int pos) {
        if (pos < 0)
            return pos;
        int c = ch - margin;
        pos = nodes[pos].nxt[c];
        return pos;
    }
    int size() { return nodes.size(); }
};

template <int char_size, int margin>
struct AhoCorasick : public Trie<char_size + 1, margin> {
    const int FAIL = char_size;
    vector<int> correct;
    void build() {
        correct.resize(this->size());
        for (int i = 0; i < this->size(); i++) {
            correct[i] = this->nodes[i].accept.size();
        }
        queue<int> que;
        for (int i = 0; i <= char_size; i++) {
            if (~this->nodes[0].nxt[i]) {
                this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0;
                que.emplace(this->nodes[0].nxt[i]);
            } else
                this->nodes[0].nxt[i] = 0;
        }
        while (!que.empty()) {
            auto& now = this->nodes[que.front()];
            int fail = now.nxt[FAIL];
            correct[que.front()] += correct[fail];
            que.pop();
            for (int i = 0; i < char_size; i++) {
                if (~now.nxt[i]) {
                    this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i];
                    auto& u = this->nodes[now.nxt[i]].accept;
                    auto& v = this->nodes[this->nodes[fail].nxt[i]].accept;
                    vector<int> accept;
                    set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));
                    u = accept;
                    que.emplace(now.nxt[i]);
                } else
                    now.nxt[i] = this->nodes[fail].nxt[i];
            }
        }
    }
    pair<int, ll> move(const char& ch, int pos = 0) {
        pos = this->nodes[pos].nxt[ch - margin];
        return {pos, correct[pos]};
    }
    pair<int, ll> move(const string& str, int pos = 0) {
        ll sum = 0;
        for (auto&& c : str) {
            auto p = move(c, pos);
            pos = p.first;
            sum += p.second;
        }
        return {pos, sum};
    }
};

int main() {
    int N, M, K;
    while (cin >> N >> M >> K, N) {
        int n_phrase = 0;
        map<string, int> mp;
        vector<string> from(N), to(N);
        vector<string> phrase;
        for (int i = 0; i < N; i++) {
            cin >> from[i] >> to[i];
            if (!mp.count(from[i])) {
                phrase.emplace_back(from[i]);
                mp[from[i]] = n_phrase++;
            }
            if (!mp.count(to[i])) {
                phrase.emplace_back(to[i]);
                mp[to[i]] = n_phrase++;
            }
        }
        vector<vector<int>> G(n_phrase + 1);
        for (int i = 0; i < N; i++) {
            G[mp[from[i]]].emplace_back(mp[to[i]]);
        }
        for (int i = 0; i < n_phrase; i++) {
            G[n_phrase].emplace_back(i);
        }
        vector<string> seasonword(K);
        AhoCorasick<26, 'a'> aho;
        for (int i = 0; i < K; i++) {
            cin >> seasonword[i];
            aho.add(seasonword[i]);
        }
        aho.build();
        map<tuple<int, int, int>, Mint> dp[510];
        dp[0][{n_phrase, 0, 0}] = 1;
        for (int len_now = 0; len_now < M; len_now++) {
            for (auto&& [key, maine] : dp[len_now]) {
                auto [phrase_now, pos_now, cnt_now] = key;
                for (auto&& phrase_nxt : G[phrase_now]) {
                    int len_nxt = len_now + phrase[phrase_nxt].size();
                    if (len_nxt > M)
                        continue;
                    auto [pos_nxt, cnt_nxt] = aho.move(phrase[phrase_nxt], pos_now);
                    cnt_nxt += cnt_now;
                    if (cnt_nxt >= 2)
                        continue;
                    dp[len_nxt][{phrase_nxt, pos_nxt, cnt_nxt}] += maine;
                }
            }
            dp[len_now].clear();
        }
        Mint ans = 0;
        for (auto&& [key, maine] : dp[M]) {
            if (get<2>(key) == 1)
                ans += maine;
        }
        cout << ans.x << endl;
    }
}
accuracy: 1
time_ms: 2720
memory_kb: 6004
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
const long long MOD = 1000000007;
int main(){
  while (true){
    int N, M, K;
    cin >> N >> M >> K;
    if (N == 0 && M == 0 && K == 0){
      break;
    }
    vector<string> A(N), B(N);
    for (int i = 0; i < N; i++){
      cin >> A[i] >> B[i];
    }
    vector<string> S(K);
    for (int i = 0; i < K; i++){
      cin >> S[i];
    }
    vector<string> C;
    C.push_back("");
    for (int i = 0; i < N; i++){
      C.push_back(A[i]);
      C.push_back(B[i]);
    }
    sort(C.begin(), C.end());
    C.erase(unique(C.begin(), C.end()), C.end());
    int V = C.size();
    vector<vector<int>> E(V);
    for (int i = 1; i < V; i++){
      E[0].push_back(i);
    }
    for (int i = 0; i < N; i++){
      int a = lower_bound(C.begin(), C.end(), A[i]) - C.begin();
      int b = lower_bound(C.begin(), C.end(), B[i]) - C.begin();
      E[a].push_back(b);
    }
    vector<string> S2;
    for (int i = 0; i < K; i++){
      int L = S[i].size();
      for (int j = 0; j <= L; j++){
        S2.push_back(S[i].substr(0, j));
      }
    }
    sort(S2.begin(), S2.end());
    S2.erase(unique(S2.begin(), S2.end()), S2.end());
    int cnt = S2.size();
    vector<int> W(cnt, 0);
    for (int i = 0; i < cnt; i++){
      for (int j = 0; j < K; j++){
        if (S2[i].size() >= S[j].size()){
          if (S2[i].substr(S2[i].size() - S[j].size()) == S[j]){
            W[i]++;
          }
        }
      }
    }
    map<string, int> mp;
    for (int i = 0; i < cnt; i++){
      mp[S2[i]] = i;
    }
    vector<vector<int>> T(cnt, vector<int>(26));
    for (int i = 0; i < cnt; i++){
      for (int j = 0; j < 26; j++){
        string X = S2[i] + (char) ('a' + j);
        int L = X.size();
        for (int k = 0; k <= L; k++){
          string X2 = X.substr(k);
          if (mp.count(X2) == 1){
            T[i][j] = mp[X2];
            break;
          }
        }
      }
    }
    vector<vector<int>> T2(cnt, vector<int>(V));
    vector<vector<int>> W2(cnt, vector<int>(V, 0));
    for (int i = 0; i < cnt; i++){
      for (int j = 0; j < V; j++){
        int c = i;
        int L = C[j].size();
        for (int k = 0; k < L; k++){
          c = T[c][C[j][k] - 'a'];
          W2[i][j] += W[c];
        }
        T2[i][j] = c;
      }
    }
    vector<vector<vector<long long>>> dp1(21, vector<vector<long long>>(cnt, vector<long long>(V, 0)));
    vector<vector<vector<long long>>> dp2(21, vector<vector<long long>>(cnt, vector<long long>(V, 0)));
    dp1[0][0][0] = 1;
    for (int i = 0; i < M; i++){
      int r = i % 21;
      for (int j = 0; j < cnt; j++){
        for (int k = 0; k < V; k++){
          for (int w : E[k]){
            int i2 = i + C[w].size();
            if (i2 <= M){
              int r2 = i2 % 21;
              int j2 = T2[j][w];
              int c = W2[j][w];
              if (c == 0){
                dp1[r2][j2][w] += dp1[r][j][k];
                dp1[r2][j2][w] %= MOD;
                dp2[r2][j2][w] += dp2[r][j][k];
                dp2[r2][j2][w] %= MOD;
              }
              if (c == 1){
                dp2[r2][j2][w] += dp1[r][j][k];
                dp2[r2][j2][w] %= MOD;
              }
            }
          }
          dp1[r][j][k] = 0;
          dp2[r][j][k] = 0;
        }
      }
    }
    long long ans = 0;
    for (int i = 0; i < cnt; i++){
      for (int j = 0; j < V; j++){
        ans += dp2[M % 21][i][j];
      }
    }
    ans %= MOD;
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 4250
memory_kb: 105184
final_rank: 11

code_snippet: #define MOD_TYPE 1

#pragma region Macros

#include <bits/stdc++.h>
using namespace std;

#if 0
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using Int = boost::multiprecision::cpp_int;
using lld = boost::multiprecision::cpp_dec_float_100;
#endif
#if 0
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#endif
using ll = long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
template <typename Q_type>
using smaller_queue = priority_queue<Q_type, vector<Q_type>, greater<Q_type>>;

constexpr ll MOD = (MOD_TYPE == 1 ? (ll)(1e9 + 7) : 998244353);
constexpr int INF = (int)1e9 + 10;
constexpr ll LINF = (ll)4e18;
constexpr ld PI = acos(-1.0);
constexpr ld EPS = 1e-7;
constexpr int Dx[] = {0, 0, -1, 1, -1, 1, -1, 1, 0};
constexpr int Dy[] = {1, -1, 0, 0, -1, -1, 1, 1, 0};

#define REP(i, m, n) for (ll i = m; i < (ll)(n); ++i)
#define rep(i, n) REP(i, 0, n)
#define REPI(i, m, n) for (int i = m; i < (int)(n); ++i)
#define repi(i, n) REPI(i, 0, n)
#define MP make_pair
#define MT make_tuple
#define YES(n) cout << ((n) ? "YES" : "NO") << "\n"
#define Yes(n) cout << ((n) ? "Yes" : "No") << "\n"
#define possible(n) cout << ((n) ? "possible" : "impossible") << "\n"
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << "\n"
#define all(v) v.begin(), v.end()
#define NP(v) next_permutation(all(v))
#define dbg(x) cerr << #x << ":" << x << "\n";

struct io_init
{
  io_init()
  {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(30) << setiosflags(ios::fixed);
  };
} io_init;
template <typename T>
inline bool chmin(T &a, T b)
{
  if (a > b)
  {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
inline bool chmax(T &a, T b)
{
  if (a < b)
  {
    a = b;
    return true;
  }
  return false;
}
inline ll CEIL(ll a, ll b)
{
  return (a + b - 1) / b;
}
template <typename A, size_t N, typename T>
inline void Fill(A (&array)[N], const T &val)
{
  fill((T *)array, (T *)(array + N), val);
}
template <typename T, typename U>
constexpr istream &operator>>(istream &is, pair<T, U> &p) noexcept
{
  is >> p.first >> p.second;
  return is;
}
template <typename T, typename U>
constexpr ostream &operator<<(ostream &os, pair<T, U> &p) noexcept
{
  os << p.first << " " << p.second;
  return os;
}
#pragma endregion

// --------------------------------------

#pragma region mint
template <int MOD>
struct Fp
{
  int val;

  constexpr Fp(int v = 0) noexcept : val(v % MOD)
  {
    if (val < 0)
      v += MOD;
  }

  constexpr int getmod()
  {
    return MOD;
  }

  constexpr Fp operator-() const noexcept
  {
    return val ? MOD - val : 0;
  }

  constexpr Fp operator+(const Fp &r) const noexcept
  {
    return Fp(*this) += r;
  }

  constexpr Fp operator-(const Fp &r) const noexcept
  {
    return Fp(*this) -= r;
  }

  constexpr Fp operator*(const Fp &r) const noexcept
  {
    return Fp(*this) *= r;
  }

  constexpr Fp operator/(const Fp &r) const noexcept
  {
    return Fp(*this) /= r;
  }

  constexpr Fp &operator+=(const Fp &r) noexcept
  {
    val += r.val;
    if (val >= MOD)
      val -= MOD;
    return *this;
  }

  constexpr Fp &operator-=(const Fp &r) noexcept
  {
    val -= r.val;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr Fp &operator*=(const Fp &r) noexcept
  {
    val = val * r.val % MOD;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr Fp &operator/=(const Fp &r) noexcept
  {
    long long a = r.val, b = MOD, u = 1, v = 0;
    while (b)
    {
      long long t = a / b;
      a -= t * b;
      swap(a, b);
      u -= t * v;
      swap(u, v);
    }
    val = val * u % MOD;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr bool operator==(const Fp &r) const noexcept
  {
    return this->val == r.val;
  }

  constexpr bool operator!=(const Fp &r) const noexcept
  {
    return this->val != r.val;
  }

  friend constexpr ostream &operator<<(ostream &os, const Fp<MOD> &x) noexcept
  {
    return os << x.val;
  }

  friend constexpr istream &operator>>(istream &is, Fp<MOD> &x) noexcept
  {
    return is >> x.val;
  }
};

Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept
{
  if (n == 0)
    return 1;
  auto t = modpow(a, n / 2);
  t = t * t;
  if (n & 1)
    t = t * a;
  return t;
}

using mint = Fp<MOD>;
#pragma endregion

template <char MIN_CHAR = 'a', int ALPHABET = 26>
struct AhoCorasick
{
  struct node
  {
    // suff : 先頭の文字を最小限消してグラフに存在する頂点にするときの行先の頂点
    // dict : 先頭の文字を最小限消して辞書に存在する単語にするときの行先の頂点
    // depth : Trie木における深さ（省略可能）
    // word_index : このノードで終わる単語のindex（祖先は含まない。なければ-1）（複数ある場合は最小のもの）
    // word_count : このノードで終わる単語の総数
    // link : Trie及びsuffixの辺の接続先頂点（なければ-1）
    int suff = -1, dict = -1, depth = 0;
    int word_index = -1, word_count = 0;
    int link[ALPHABET];
    node() { fill(link, link + ALPHABET, -1); }
    int &operator[](char c) { return link[c - MIN_CHAR]; }
  };

  // nodes : 頂点集合
  // W : 現在の単語数
  // word_location : 各単語のTrie木の最後の頂点のindex
  // defer : 同じ単語が辞書内に存在する場合、最初の単語のindexを記録
  vector<node> nodes;
  int W;
  vector<int> word_location;
  vector<int> word_indices_by_depth;
  vector<int> defer;

  AhoCorasick(){};
  AhoCorasick(const vector<string> &words = {})
  {
    build(words);
  }

  // suffixを親とする木の隣接リスト これの上でDPやクエリ処理を行うことが多い
  vector<vector<int>> build_suffix_adj() const
  {
    vector<vector<int>> adj(nodes.size());
    for (int i = 1; i < int(nodes.size()); i++)
      adj[nodes[i].suff].push_back(i);
    return adj;
  }

  int get_or_add_child(int current, char c)
  {
    if (nodes[current][c] >= 0)
      return nodes[current][c];
    int index = int(nodes.size());
    nodes[current][c] = index;
    nodes.emplace_back();
    nodes.back().depth = nodes[current].depth + 1;
    return index;
  }

  int add_word(const string &word, int word_index)
  {
    assert(!nodes.empty());
    int current = 0;
    for (char c : word)
      current = get_or_add_child(current, c);
    if (nodes[current].word_index < 0)
      nodes[current].word_index = word_index;
    nodes[current].word_count++;
    return current;
  }

  // locationからcを追加したときの行き先 O(1)
  int get_suffix_link(int location, char c) const
  {
    if (location >= 0)
      location = nodes[location].link[c - MIN_CHAR];
    return max(location, 0);
  }

  void build(const vector<string> &words)
  {
    nodes = {node()};
    W = int(words.size());
    word_location.resize(W);
    defer.resize(W);
    int max_depth = 0;

    for (int i = 0; i < W; i++)
    {
      word_location[i] = add_word(words[i], i);
      max_depth = max(max_depth, int(words[i].size()));
      defer[i] = nodes[word_location[i]].word_index;
    }

    // depthの降順に単語indexのリストを作成
    word_indices_by_depth.resize(W);
    vector<int> depth_freq(max_depth + 1, 0);

    for (int i = 0; i < W; i++)
      depth_freq[words[i].size()]++;

    for (int i = max_depth - 1; i >= 0; i--)
      depth_freq[i] += depth_freq[i + 1];

    for (int i = 0; i < W; i++)
      word_indices_by_depth[--depth_freq[words[i].size()]] = i;

    // depth順のBFSでsuffix parentを求める
    vector<int> q = {0};

    for (int i = 0; i < int(q.size()); i++)
    {
      int current = q[i];

      for (char c = MIN_CHAR; c < MIN_CHAR + ALPHABET; c++)
      {
        int &index = nodes[current][c];
        if (index >= 0)
        {
          // currentのsuffix parentで子cを持つものが見つかるまで走査して
          // indexのsuffix parentを見つける
          int suffix_parent = get_suffix_link(nodes[current].suff, c);
          nodes[index].suff = suffix_parent;
          nodes[index].word_count += nodes[suffix_parent].word_count;
          nodes[index].dict = nodes[suffix_parent].word_index < 0 ? nodes[suffix_parent].dict : suffix_parent;
          q.push_back(index);
        }
        else
        {
          index = get_suffix_link(nodes[current].suff, c);
        }
      }
    }
  }

  // 辞書内のそれぞれの単語がtextに何個含まれているか O(text length + num words)
  vector<int> count_matches(const string &text) const
  {
    vector<int> matches(W, 0);
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      int dict_node = nodes[current].word_index < 0 ? nodes[current].dict : current;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index]++;
    }

    // depthの降順に見る
    for (int word_index : word_indices_by_depth)
    {
      int location = word_location[word_index];
      int dict_node = nodes[location].dict;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index] += matches[word_index];
    }

    for (int i = 0; i < W; i++)
      matches[i] = matches[defer[i]];

    return matches;
  }

  // textに含まれる辞書内の単語で、textのi文字目で終わるものの個数 O(text length)
  vector<int> count_matches_by_position(const string &text) const
  {
    vector<int> matches(text.size());
    int current = 0;

    for (int i = 0; i < int(text.size()); i++)
    {
      current = get_suffix_link(current, text[i]);
      matches[i] = nodes[current].word_count;
    }

    return matches;
  }

  // textに辞書内の単語が合計何個含まれているか O(text length)
  int64_t count_total_matches(const string &text) const
  {
    int64_t matches = 0;
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      matches += nodes[current].word_count;
    }

    return matches;
  }
};

void solve(int n, int m, int k)
{
  vector<string> from(n), to(n);
  rep(i, n) cin >> from[i] >> to[i];
  map<string, int> mp;
  for (auto &&s : from)
    mp[s] = 0;
  for (auto &&s : to)
    mp[s] = 0;
  mp[""] = 0;
  int z = 0;
  for (auto &&[k, v] : mp)
    v = z++;

  vector<string> mpr(z);
  for (auto &&[k, v] : mp)
    mpr[v] = k;

  vector E(z, vector<int>());
  rep(i, n)
  {
    E[mp[from[i]]].push_back(mp[to[i]]);
  }
  REP(i, 1, z)
  {
    E[0].push_back(i);
  }

  vector<string> seasonword(k);
  rep(i, k) cin >> seasonword[i];
  AhoCorasick<> aho(seasonword);

  auto next_state = [&](int state, int nxt_vertex) {
    int cnt = 0;
    for (auto c : mpr[nxt_vertex])
    {
      state = aho.get_suffix_link(state, c);
      cnt += aho.nodes[state].word_count;
      if (cnt > 1)
      {
        cnt = 2;
        state = -1;
        break;
      }
    }
    return MP(state, cnt);
  };

  vector nxt(aho.nodes.size(), vector<int>(z));
  vector season(aho.nodes.size(), vector<int>(z));
  map<tuple<int, int, int, bool>, mint> dp;

  rep(state, aho.nodes.size())
  {
    REP(nxt_vertex, 1, z)
    {
      auto [p, q] = next_state(state, nxt_vertex);
      nxt[state][nxt_vertex] = p;
      season[state][nxt_vertex] = q;
    }
  }

  dp[MT(0, 0, 0, false)] = 1;

  for (auto [key, val] : dp)
  {
    auto [i, vertex, state, l] = key;
    for (auto nxt_vertex : E[vertex])
    {
      if (season[state][nxt_vertex] == 2)
        continue;
      int j = i + mpr[nxt_vertex].length();
      if (j > m)
        continue;
      if (season[state][nxt_vertex] == 1)
      {
        if (l == 0)
          dp[MT(j, nxt_vertex, nxt[state][nxt_vertex], true)] += val;
      }
      else
      {
        if (l == 0)
          dp[MT(j, nxt_vertex, nxt[state][nxt_vertex], false)] += val;
        else if (l == 1)
          dp[MT(j, nxt_vertex, nxt[state][nxt_vertex], true)] += val;
      }
    }
  }

  mint ans = 0;
  rep(vertex, z) rep(state, aho.nodes.size())
  {
    if (dp.count(MT(m, vertex, state, true)))
      ans += dp[MT(m, vertex, state, true)];
  }
  cout << ans << "\n";
}

int main()
{
  int n, m, k;
  while (1)
  {
    cin >> n >> m >> k;
    if (n == 0)
      break;
    solve(n, m, k);
  }
}
accuracy: 1
time_ms: 2600
memory_kb: 201392
final_rank: 15

code_snippet: #define MOD_TYPE 1

#pragma region Macros

#include <bits/stdc++.h>
using namespace std;

#if 0
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using Int = boost::multiprecision::cpp_int;
using lld = boost::multiprecision::cpp_dec_float_100;
#endif
#if 0
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#endif
using ll = long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
template <typename Q_type>
using smaller_queue = priority_queue<Q_type, vector<Q_type>, greater<Q_type>>;

constexpr ll MOD = (MOD_TYPE == 1 ? (ll)(1e9 + 7) : 998244353);
constexpr int INF = (int)1e9 + 10;
constexpr ll LINF = (ll)4e18;
constexpr ld PI = acos(-1.0);
constexpr ld EPS = 1e-7;
constexpr int Dx[] = {0, 0, -1, 1, -1, 1, -1, 1, 0};
constexpr int Dy[] = {1, -1, 0, 0, -1, -1, 1, 1, 0};

#define REP(i, m, n) for (ll i = m; i < (ll)(n); ++i)
#define rep(i, n) REP(i, 0, n)
#define REPI(i, m, n) for (int i = m; i < (int)(n); ++i)
#define repi(i, n) REPI(i, 0, n)
#define MP make_pair
#define MT make_tuple
#define YES(n) cout << ((n) ? "YES" : "NO") << "\n"
#define Yes(n) cout << ((n) ? "Yes" : "No") << "\n"
#define possible(n) cout << ((n) ? "possible" : "impossible") << "\n"
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << "\n"
#define all(v) v.begin(), v.end()
#define NP(v) next_permutation(all(v))
#define dbg(x) cerr << #x << ":" << x << "\n";

struct io_init
{
  io_init()
  {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(30) << setiosflags(ios::fixed);
  };
} io_init;
template <typename T>
inline bool chmin(T &a, T b)
{
  if (a > b)
  {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
inline bool chmax(T &a, T b)
{
  if (a < b)
  {
    a = b;
    return true;
  }
  return false;
}
inline ll CEIL(ll a, ll b)
{
  return (a + b - 1) / b;
}
template <typename A, size_t N, typename T>
inline void Fill(A (&array)[N], const T &val)
{
  fill((T *)array, (T *)(array + N), val);
}
template <typename T, typename U>
constexpr istream &operator>>(istream &is, pair<T, U> &p) noexcept
{
  is >> p.first >> p.second;
  return is;
}
template <typename T, typename U>
constexpr ostream &operator<<(ostream &os, pair<T, U> &p) noexcept
{
  os << p.first << " " << p.second;
  return os;
}
#pragma endregion

// --------------------------------------

#pragma region mint
template <int MOD>
struct Fp
{
  int val;

  constexpr Fp(int v = 0) noexcept : val(v % MOD)
  {
    if (val < 0)
      v += MOD;
  }

  constexpr int getmod()
  {
    return MOD;
  }

  constexpr Fp operator-() const noexcept
  {
    return val ? MOD - val : 0;
  }

  constexpr Fp operator+(const Fp &r) const noexcept
  {
    return Fp(*this) += r;
  }

  constexpr Fp operator-(const Fp &r) const noexcept
  {
    return Fp(*this) -= r;
  }

  constexpr Fp operator*(const Fp &r) const noexcept
  {
    return Fp(*this) *= r;
  }

  constexpr Fp operator/(const Fp &r) const noexcept
  {
    return Fp(*this) /= r;
  }

  constexpr Fp &operator+=(const Fp &r) noexcept
  {
    val += r.val;
    if (val >= MOD)
      val -= MOD;
    return *this;
  }

  constexpr Fp &operator-=(const Fp &r) noexcept
  {
    val -= r.val;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr Fp &operator*=(const Fp &r) noexcept
  {
    val = val * r.val % MOD;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr Fp &operator/=(const Fp &r) noexcept
  {
    long long a = r.val, b = MOD, u = 1, v = 0;
    while (b)
    {
      long long t = a / b;
      a -= t * b;
      swap(a, b);
      u -= t * v;
      swap(u, v);
    }
    val = val * u % MOD;
    if (val < 0)
      val += MOD;
    return *this;
  }

  constexpr bool operator==(const Fp &r) const noexcept
  {
    return this->val == r.val;
  }

  constexpr bool operator!=(const Fp &r) const noexcept
  {
    return this->val != r.val;
  }

  friend constexpr ostream &operator<<(ostream &os, const Fp<MOD> &x) noexcept
  {
    return os << x.val;
  }

  friend constexpr istream &operator>>(istream &is, Fp<MOD> &x) noexcept
  {
    return is >> x.val;
  }
};

Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept
{
  if (n == 0)
    return 1;
  auto t = modpow(a, n / 2);
  t = t * t;
  if (n & 1)
    t = t * a;
  return t;
}

using mint = Fp<MOD>;
#pragma endregion

template <char MIN_CHAR = 'a', int ALPHABET = 26>
struct AhoCorasick
{
  struct node
  {
    // suff : 先頭の文字を最小限消してグラフに存在する頂点にするときの行先の頂点
    // dict : 先頭の文字を最小限消して辞書に存在する単語にするときの行先の頂点
    // depth : Trie木における深さ（省略可能）
    // word_index : このノードで終わる単語のindex（祖先は含まない。なければ-1）（複数ある場合は最小のもの）
    // word_count : このノードで終わる単語の総数
    // link : Trie及びsuffixの辺の接続先頂点（なければ-1）
    int suff = -1, dict = -1, depth = 0;
    int word_index = -1, word_count = 0;
    int link[ALPHABET];
    node() { fill(link, link + ALPHABET, -1); }
    int &operator[](char c) { return link[c - MIN_CHAR]; }
  };

  // nodes : 頂点集合
  // W : 現在の単語数
  // word_location : 各単語のTrie木の最後の頂点のindex
  // defer : 同じ単語が辞書内に存在する場合、最初の単語のindexを記録
  vector<node> nodes;
  int W;
  vector<int> word_location;
  vector<int> word_indices_by_depth;
  vector<int> defer;

  AhoCorasick(){};
  AhoCorasick(const vector<string> &words = {})
  {
    build(words);
  }

  // suffixを親とする木の隣接リスト これの上でDPやクエリ処理を行うことが多い
  vector<vector<int>> build_suffix_adj() const
  {
    vector<vector<int>> adj(nodes.size());
    for (int i = 1; i < int(nodes.size()); i++)
      adj[nodes[i].suff].push_back(i);
    return adj;
  }

  int get_or_add_child(int current, char c)
  {
    if (nodes[current][c] >= 0)
      return nodes[current][c];
    int index = int(nodes.size());
    nodes[current][c] = index;
    nodes.emplace_back();
    nodes.back().depth = nodes[current].depth + 1;
    return index;
  }

  int add_word(const string &word, int word_index)
  {
    assert(!nodes.empty());
    int current = 0;
    for (char c : word)
      current = get_or_add_child(current, c);
    if (nodes[current].word_index < 0)
      nodes[current].word_index = word_index;
    nodes[current].word_count++;
    return current;
  }

  // locationからcを追加したときの行き先 O(1)
  int get_suffix_link(int location, char c) const
  {
    if (location >= 0)
      location = nodes[location].link[c - MIN_CHAR];
    return max(location, 0);
  }

  void build(const vector<string> &words)
  {
    nodes = {node()};
    W = int(words.size());
    word_location.resize(W);
    defer.resize(W);
    int max_depth = 0;

    for (int i = 0; i < W; i++)
    {
      word_location[i] = add_word(words[i], i);
      max_depth = max(max_depth, int(words[i].size()));
      defer[i] = nodes[word_location[i]].word_index;
    }

    // depthの降順に単語indexのリストを作成
    word_indices_by_depth.resize(W);
    vector<int> depth_freq(max_depth + 1, 0);

    for (int i = 0; i < W; i++)
      depth_freq[words[i].size()]++;

    for (int i = max_depth - 1; i >= 0; i--)
      depth_freq[i] += depth_freq[i + 1];

    for (int i = 0; i < W; i++)
      word_indices_by_depth[--depth_freq[words[i].size()]] = i;

    // depth順のBFSでsuffix parentを求める
    vector<int> q = {0};

    for (int i = 0; i < int(q.size()); i++)
    {
      int current = q[i];

      for (char c = MIN_CHAR; c < MIN_CHAR + ALPHABET; c++)
      {
        int &index = nodes[current][c];
        if (index >= 0)
        {
          // currentのsuffix parentで子cを持つものが見つかるまで走査して
          // indexのsuffix parentを見つける
          int suffix_parent = get_suffix_link(nodes[current].suff, c);
          nodes[index].suff = suffix_parent;
          nodes[index].word_count += nodes[suffix_parent].word_count;
          nodes[index].dict = nodes[suffix_parent].word_index < 0 ? nodes[suffix_parent].dict : suffix_parent;
          q.push_back(index);
        }
        else
        {
          index = get_suffix_link(nodes[current].suff, c);
        }
      }
    }
  }

  // 辞書内のそれぞれの単語がtextに何個含まれているか O(text length + num words)
  vector<int> count_matches(const string &text) const
  {
    vector<int> matches(W, 0);
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      int dict_node = nodes[current].word_index < 0 ? nodes[current].dict : current;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index]++;
    }

    // depthの降順に見る
    for (int word_index : word_indices_by_depth)
    {
      int location = word_location[word_index];
      int dict_node = nodes[location].dict;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index] += matches[word_index];
    }

    for (int i = 0; i < W; i++)
      matches[i] = matches[defer[i]];

    return matches;
  }

  // textに含まれる辞書内の単語で、textのi文字目で終わるものの個数 O(text length)
  vector<int> count_matches_by_position(const string &text) const
  {
    vector<int> matches(text.size());
    int current = 0;

    for (int i = 0; i < int(text.size()); i++)
    {
      current = get_suffix_link(current, text[i]);
      matches[i] = nodes[current].word_count;
    }

    return matches;
  }

  // textに辞書内の単語が合計何個含まれているか O(text length)
  int64_t count_total_matches(const string &text) const
  {
    int64_t matches = 0;
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      matches += nodes[current].word_count;
    }

    return matches;
  }
};

mint dp[21][501][601][2];

void solve(int n, int m, int k)
{
  vector<string> from(n), to(n);
  rep(i, n) cin >> from[i] >> to[i];
  map<string, int> mp;
  for (auto &&s : from)
    mp[s] = 0;
  for (auto &&s : to)
    mp[s] = 0;
  mp[""] = 0;
  int z = 0;
  for (auto &&[k, v] : mp)
    v = z++;

  vector<string> mpr(z);
  for (auto &&[k, v] : mp)
    mpr[v] = k;

  vector Erev(z, vector<int>());
  rep(i, n)
  {
    Erev[mp[to[i]]].push_back(mp[from[i]]);
  }
  REP(i, 1, z)
  {
    Erev[i].push_back(0);
  }

  vector<string> seasonword(k);
  rep(i, k) cin >> seasonword[i];
  AhoCorasick<> aho(seasonword);

  auto next_state = [&](int state, int nxt_vertex) {
    int cnt = 0;
    for (auto c : mpr[nxt_vertex])
    {
      state = aho.get_suffix_link(state, c);
      cnt += aho.nodes[state].word_count;
      if (cnt > 1)
      {
        cnt = 2;
        state = -1;
        break;
      }
    }
    return MP(state, cnt);
  };

  vector nxt(aho.nodes.size(), vector<int>(z));
  vector season(aho.nodes.size(), vector<int>(z));

  rep(state, aho.nodes.size())
  {
    REP(nxt_vertex, 1, z)
    {
      auto [p, q] = next_state(state, nxt_vertex);
      nxt[state][nxt_vertex] = p;
      season[state][nxt_vertex] = q;
    }
  }

  rep(i, 21) rep(j, z) rep(k, aho.nodes.size()) rep(l, 2) dp[i][j][k][l] = 0;
  dp[0][0][0][0] = 1;
  REP(i, 1, m + 1)
  {
    rep(j, z) rep(k, aho.nodes.size()) rep(l, 2) dp[i % 21][j][k][l] = 0;
    rep(vertex, z)
    {
      rep(state, aho.nodes.size())
      {
        for (auto prev_vertex : Erev[vertex])
        {
          if (season[state][vertex] == 2)
            continue;
          int j = (i - int(mpr[vertex].length())) % 21;
          if (j < 0)
            j += 21;
          if (season[state][vertex] == 1)
          {
            dp[i % 21][vertex][nxt[state][vertex]][1] += dp[j][prev_vertex][state][0];
          }
          else
          {
            dp[i % 21][vertex][nxt[state][vertex]][0] += dp[j][prev_vertex][state][0];
            dp[i % 21][vertex][nxt[state][vertex]][1] += dp[j][prev_vertex][state][1];
          }
        }
      }
    }
  }

  mint ans = 0;
  rep(vertex, z) rep(state, aho.nodes.size())
  {
    ans += dp[m % 21][vertex][state][1];
  }
  cout << ans << "\n";
}

int main()
{
  int n, m, k;
  while (1)
  {
    cin >> n >> m >> k;
    if (n == 0)
      break;
    solve(n, m, k);
  }
}
accuracy: 1
time_ms: 1770
memory_kb: 55176
final_rank: 3

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 18;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

modint dp[605][21][505][2];
struct AhoCorasick {
	static const int SIZE = 27;
	struct State {
		int index, next[SIZE];
		//vector<int> accept;
		State(int index) : index(index) {
			for (int i = 0; i < SIZE; i++)next[i] = -1;
		}
	};
	vector<State> pma;
	//vector<int> lens;

	AhoCorasick(const vector<string>& str, char base_c = 'a') {
		pma.clear();
		pma.push_back(State(0));
		//lens.clear();
		rep(i, str.size()) {
			int t = 0;
			for (char c : str[i]) {
				if (pma[t].next[c - base_c] == -1) {
					int m = pma.size();
					pma[t].next[c - base_c] = m;
					pma.push_back(State(m));
				}
				t = pma[t].next[c - base_c];
			}
			//pma[t].accept.push_back(lens.size());
			//lens.push_back(str[i].size());
		}
		queue<int> que;
		for (int c = 0; c < SIZE - 1; c++) {
			if (pma[0].next[c] != -1) {
				pma[pma[0].next[c]].next[SIZE - 1] = 0;
				que.push(pma[0].next[c]);
			}
			else {
				pma[0].next[c] = 0;
			}
		}
		while (!que.empty()) {
			int t = que.front();
			que.pop();
			for (int c = 0; c < SIZE - 1; c++) {
				if (pma[t].next[c] != -1) {
					que.push(pma[t].next[c]);
					int r = pma[t].next[SIZE - 1];
					while (pma[r].next[c] == -1) r = pma[r].next[SIZE - 1];
					pma[pma[t].next[c]].next[SIZE - 1] = pma[r].next[c];
					//for (int i : pma[pma[r].next[c]].accept)
					//	pma[pma[t].next[c]].accept.push_back(i);
				}
			}
		}
	}
	int sub(int index, int c) {
		return pma[index].next[c] != -1 ?
			pma[index].next[c] :
			pma[index].next[c] = sub(pma[index].next[SIZE - 1], c);
	}
	vector<int> fincnt;
	void init_fin(vector<string> s) {
		fincnt.resize(pma.size(), 0);
		rep(i, s.size()) {
			int loc = 0;
			rep(j, s[i].size()) {
				loc = pma[loc].next[s[i][j] - 'a'];
			}
			fincnt[loc] = true;
		}
		rep(i, pma.size()) {
			if (pma[i].next[26] >= 0) {
				fincnt[i] += fincnt[pma[i].next[26]];
			}
		}
	}
	int query(vector<string> a,vector<string> b, int m) {
		vector<string> s;
		rep(i, a.size()) {
			s.push_back(a[i]);
			s.push_back(b[i]);
		}
		sort(all(s));
		s.erase(unique(all(s)), s.end());
		int n = s.size();
		vector<vector<int>> G(n);
		rep(i, a.size()) {
			int le = lower_bound(all(s), a[i]) - s.begin();
			int ri = lower_bound(all(s), b[i]) - s.begin();
			G[le].push_back(ri);
		}
		vector<vector<int>> nex(pma.size(), vector<int>(n));
		vector<vector<int>> ad(pma.size(), vector<int>(n));
		rep(i, pma.size())rep(j, 21)rep(k, n)rep(l, 2)dp[i][j][k][l] = 0;
		rep(i, pma.size()) {
			rep(j, n) {
				int loc = i;
				int cnt = 0;
				rep(k, s[j].size()) {
					loc = sub(loc, s[j][k] - 'a');
					cnt += fincnt[loc];
				}
				nex[i][j] = loc;
				ad[i][j] = cnt;
			}
		}
		rep(i, n) {
			int ni = nex[0][i];
			int nj = s[i].size();
			int nk = i;
			int nl = ad[0][i];
			if (nl < 2) {
				dp[ni][nj][nk][nl] += 1;
			}
		}
		rep(j, m) {
			rep(i, pma.size()) {
				rep(k, n) {
					rep(l, 2) {
						if (dp[i][j%21][k][l] == (modint)0)continue;
						for (int t : G[k]) {
							int ni = nex[i][t];
							int nj = (j + s[t].size())%21;
							int nk = t;
							int nl = l + ad[i][t];
							if (nl < 2) {
								dp[ni][nj][nk][nl] += dp[i][j%21][k][l];
							}
						}
						dp[i][j%21][k][l] = 0;
					}
				}
			}
		}
		modint res = 0;
		rep(i, pma.size())rep(j,n) {
			res += dp[i][m%21][j][1];
		}
		return res;
	}
};



int n, m, k;
void solve() {
	vector<string> a(n),b(n);
	vector<string> w(k);
	rep(i, n)cin >> a[i] >> b[i];
	rep(i, k)cin >> w[i];
	AhoCorasick aho(w);
	aho.init_fin(w);
	int ans = aho.query(a, b, m);
	cout << ans << "\n";
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
	//init();
	//expr();
	//int t; cin >> t;rep(i,t)
	while(cin>>n>>m>>k,n)
	solve();
	return 0;
}
accuracy: 1
time_ms: 430
memory_kb: 109940
final_rank: 5

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>


class AhoCorasick {
public:
	struct Node;
private:
	std::shared_ptr<Node> root;
	Node* current;
	AhoCorasick(std::shared_ptr<Node>&& root, Node* current) : root{ std::move(root) }, current{ current }{};
	AhoCorasick(const std::shared_ptr<Node>& root, Node* current) : root{ root }, current{ current }{};
public:
	static AhoCorasick create(const std::vector<std::string>& str) {
		auto root = std::make_shared<Node>();
		for (const auto& s : str) {
			Node* current = root.get();
			for (const auto c : s) {
				if (current->child[c - 'a'] != nullptr) {
					current = current->child[c - 'a'].get();
				}
				else {
					current->child[c - 'a'] = std::make_unique<Node>();
					current = current->child[c - 'a'].get();
				}
			}
			current->match_count++;
		}
		std::queue<Node*> queue;
		for (auto c = 'a'; c <= 'z'; ++c) {
			if (root->child[c - 'a'] != nullptr) {
				const auto child = root->child[c - 'a'].get();
				child->fail = root.get();
				queue.emplace(child);
			}
		}
		while (!queue.empty()) {
			const auto current = queue.front(); queue.pop();
			for (auto c = 'a'; c <= 'z'; ++c) {
				if (current->child[c - 'a'] != nullptr) {
					const auto child = current->child[c - 'a'].get();
					child->fail = current->fail->next(c);
					child->match_count += child->fail->match_count;
					queue.push(child);
				}
			}
		}
		auto ptr = root.get();
		return AhoCorasick{ std::move(root), ptr };

	}
	struct Node {
		int match_count{ 0 };
		Node* fail{ nullptr };
		std::vector<std::unique_ptr<Node>> child;
		Node() : child(26) {};
		Node* next(const char c) {
			if (child[c - 'a'] == nullptr) {
				return fail == nullptr ? this : fail->next(c);
			}
			else {
				return child[c - 'a'].get();
			}
		}
	};
	AhoCorasick next(const char c) const {
		return AhoCorasick(root, current->next(c));
	}
	Node* node() const {
		return current;
	}
};
void solve(const int n, const int m, const int k){
	std::vector<std::pair<std::string, std::string>> pairs(n);
	for (auto& [from, to] : pairs) {
		std::cin >> from >> to;
	}
	std::vector<std::string> words;
	for (const auto& [from, to] : pairs) {
		words.push_back(from);
		words.push_back(to);
	}
	std::sort(words.begin(), words.end());
	words.erase(std::unique(words.begin(), words.end()), words.end());
	std::unordered_map<std::string, int> to_index;
	for (auto i = 0; i < words.size(); ++i) {
		to_index[words[i]] = i;
	}
	std::vector<std::vector<int>> succ_word(words.size());
	for (const auto& [from, to] : pairs) {
		succ_word[to_index[from]].push_back(to_index[to]);
	}
	std::vector<std::string> seasonwords(k);
	for (auto& s : seasonwords) {
		std::cin >> s;
	}
	AhoCorasick aho = AhoCorasick::create(seasonwords);
	std::vector<std::vector<std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>>> count(2, std::vector<std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>>(words.size(), std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>(m)));
	const auto comparator = [](const std::tuple<int, int, int, AhoCorasick::Node*>& a, const std::tuple<int, int, int, AhoCorasick::Node*>& b) {
		return std::get<2>(a) > std::get<2>(b);
	};
	std::priority_queue<std::tuple<int, int, int, AhoCorasick::Node*>, std::vector<std::tuple<int, int, int, AhoCorasick::Node*>>, decltype(comparator)> queue(comparator);
	constexpr long long int mod = 1000000007;
	long long int result = 0;
	for (auto i = 0; i < words.size(); ++i) {
		if (words[i].size() > m) continue;
		int match = 0;
		auto current = aho.node();
		for (const auto& c : words[i]) {
			current = current->next(c);
			match += current->match_count;
		}
		if (match > 1) continue;
		if (words[i].size() == m) {
			if (match == 1) ++result;
		}
		else {
			count[match][i][words[i].size()][current] += 1;
			queue.emplace(match, i, (int)words[i].size(), current);
		}
	}
	while (!queue.empty()) {
		const auto [match_count, from, length, node] = queue.top(); queue.pop();
		const auto pat = count[match_count][from][length][node] % mod;
		for (const auto to : succ_word[from]) {
			if (length + words[to].size() > m) continue;
			int match = match_count;
			auto current = node;
			for (const auto& c : words[to]) {
				current = current->next(c);
				match += current->match_count;
			}
			if (match > 1) continue;
			if (length + words[to].size() == m) {
				if (match == 1) 
					result = (result + pat) % mod;
			}
			else {
				if (count[match][to][length + words[to].size()].find(current) == count[match][to][length + words[to].size()].end()) {
					queue.emplace(match, to, length + (int)words[to].size(), current);
				}
				count[match][to][length + words[to].size()][current] += pat;
			}
		}
	}
	std::cout << result << '\n';

}
int main() {
	while (true) {
		int n, m, k;
		std::cin >> n >> m >> k;
		if (n == 0 && m == 0 && k == 0)
			break;
		solve(n, m, k);
	}
}

//https://onlinejudge.u-aizu.ac.jp/challenges/sources/JAG/Prelim/2257?year=2011
accuracy: 1
time_ms: 2580
memory_kb: 140644
final_rank: 9

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>


class AhoCorasick {
public:
	struct Node;
private:
	std::shared_ptr<Node> root;
	Node* current;
	AhoCorasick(std::shared_ptr<Node>&& root, Node* current) : root{ std::move(root) }, current{ current }{};
	AhoCorasick(const std::shared_ptr<Node>& root, Node* current) : root{ root }, current{ current }{};
public:
	static AhoCorasick create(const std::vector<std::string>& str) {
		auto root = std::make_shared<Node>();
		for (const auto& s : str) {
			Node* current = root.get();
			for (const auto c : s) {
				if (current->child[c - 'a'] != nullptr) {
					current = current->child[c - 'a'].get();
				}
				else {
					current->child[c - 'a'] = std::make_shared<Node>();
					current = current->child[c - 'a'].get();
				}
			}
			current->match_count++;
		}
		std::queue<Node*> queue;
		for (auto c = 'a'; c <= 'z'; ++c) {
			if (root->child[c - 'a'] != nullptr) {
				const auto child = root->child[c - 'a'].get();
				child->fail = root.get();
				queue.emplace(child);
			}
		}
		while (!queue.empty()) {
			const auto current = queue.front(); queue.pop();
			for (auto c = 'a'; c <= 'z'; ++c) {
				if (current->child[c - 'a'] != nullptr) {
					const auto child = current->child[c - 'a'].get();
					child->fail = current->fail->next(c);
					child->match_count += child->fail->match_count;
					queue.push(child);
				}
			}
		}
		auto ptr = root.get();
		return AhoCorasick{ std::move(root), ptr };

	}
	struct Node {
		int match_count{ 0 };
		Node* fail{ nullptr };
		std::vector<std::shared_ptr<Node>> child;
		Node() : child(26, nullptr) {};
		Node* next(const char c) {
			if (child[c - 'a'] == nullptr) {
				return fail == nullptr ? this : fail->next(c);
			}
			else {
				return child[c - 'a'].get();
			}
		}
	};
	AhoCorasick next(const char c) const {
		return AhoCorasick(root, current->next(c));
	}
	Node* node() const {
		return current;
	}
};
void solve(const int n, const int m, const int k){
	std::vector<std::pair<std::string, std::string>> pairs(n);
	for (auto& [from, to] : pairs) {
		std::cin >> from >> to;
	}
	std::vector<std::string> words;
	for (const auto& [from, to] : pairs) {
		words.push_back(from);
		words.push_back(to);
	}
	std::sort(words.begin(), words.end());
	words.erase(std::unique(words.begin(), words.end()), words.end());
	std::unordered_map<std::string, int> to_index;
	for (auto i = 0; i < words.size(); ++i) {
		to_index[words[i]] = i;
	}
	std::vector<std::vector<int>> succ_word(words.size());
	for (const auto& [from, to] : pairs) {
		succ_word[to_index[from]].push_back(to_index[to]);
	}
	std::vector<std::string> seasonwords(k);
	for (auto& s : seasonwords) {
		std::cin >> s;
	}
	AhoCorasick aho = AhoCorasick::create(seasonwords);
	std::vector<std::vector<std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>>> count(2, std::vector<std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>>(words.size(), std::vector<std::unordered_map<AhoCorasick::Node*, long long int>>(m)));
	const auto comparator = [](const std::tuple<int, int, int, AhoCorasick::Node*>& a, const std::tuple<int, int, int, AhoCorasick::Node*>& b) {
		return std::get<2>(a) > std::get<2>(b);
	};
	std::priority_queue<std::tuple<int, int, int, AhoCorasick::Node*>, std::vector<std::tuple<int, int, int, AhoCorasick::Node*>>, decltype(comparator)> queue(comparator);
	constexpr long long int mod = 1000000007;
	long long int result = 0;
	for (auto i = 0; i < words.size(); ++i) {
		if (words[i].size() > m) continue;
		int match = 0;
		auto current = aho.node();
		for (const auto& c : words[i]) {
			current = current->next(c);
			match += current->match_count;
		}
		if (match > 1) continue;
		if (words[i].size() == m) {
			if (match == 1) ++result;
		}
		else {
			count[match][i][words[i].size()][current] += 1;
			queue.emplace(match, i, (int)words[i].size(), current);
		}
	}
	while (!queue.empty()) {
		const auto [match_count, from, length, node] = queue.top(); queue.pop();
		const auto pat = count[match_count][from][length][node] % mod;
		for (const auto to : succ_word[from]) {
			if (length + words[to].size() > m) continue;
			int match = match_count;
			auto current = node;
			for (const auto& c : words[to]) {
				current = current->next(c);
				match += current->match_count;
			}
			if (match > 1) continue;
			if (length + words[to].size() == m) {
				if (match == 1) 
					result = (result + pat) % mod;
			}
			else {
				if (count[match][to][length + words[to].size()].find(current) == count[match][to][length + words[to].size()].end()) {
					queue.emplace(match, to, length + words[to].size(), current);
				}
				count[match][to][length + words[to].size()][current] += pat;
			}
		}
	}
	std::cout << result << '\n';

}
int main() {
	while (true) {
		int n, m, k;
		std::cin >> n >> m >> k;
		if (n == 0 && m == 0 && k == 0)
			break;
		solve(n, m, k);
	}
}

//https://onlinejudge.u-aizu.ac.jp/challenges/sources/JAG/Prelim/2257?year=2011
accuracy: 1
time_ms: 2590
memory_kb: 140836
final_rank: 10