#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const double EPS = 1e-8; static const double PI = 4.0 * atan(1.0); static const double PI2 = 8.0 * atan(1.0); typedef long long ll; typedef unsigned long long ull; #define ALL(c) (c).begin(), (c).end() #define CLEAR(v) memset(v,0,sizeof(v)) #define MP(a,b) make_pair((a),(b)) #define REP(i,n) for(int i=0;i<(int)n;++i) #define ABS(a) ((a)>0?(a):-(a)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) static const int kMod = 1000000007; static int numberOfPma = 0; struct PMA { PMA *next[0x100]; // next[0] is for fail vector accept; PMA() { fill(next, next+0x100, (PMA*)0); } virtual ~PMA() { REP(i, 0x100) { if (next[i]) { delete(next[i]); next[i] = NULL; } } } }; PMA *buildPMA(const vector& p) { const int size = p.size(); PMA *root = new PMA; for (int i = 0; i < size; ++i) { // make trie PMA *t = root; for (int j = 0; p[i][j]; ++j) { char c = p[i][j]; if (t->next[c] == NULL) t->next[c] = new PMA; t = t->next[c]; } t->accept.push_back(i); } queue Q; // make failure link using bfs for (int c = 'a'; c <= 'z'; ++c) { if (root->next[c]) { root->next[c]->next[0] = root; Q.push(root->next[c]); } else root->next[c] = root; } while (!Q.empty()) { PMA *t = Q.front(); Q.pop(); for (int c = 'a'; c <= 'z'; ++c) { if (t->next[c]) { Q.push(t->next[c]); PMA *r = t->next[0]; while (!r->next[c]) r = r->next[0]; t->next[c]->next[0] = r->next[c]; } } t->accept.insert(t->accept.end(), t->next[0]->accept.begin(), t->next[0]->accept.end()); } return root; } struct Dictionary { vector indexToWord; map wordToIndex; const string& toWord(int index) const { return indexToWord[index]; } int toIndex(const string& word) { if (wordToIndex.count(word)) { return wordToIndex[word]; } else { const int index = indexToWord.size(); wordToIndex.insert(MP(word, index)); indexToWord.push_back(word); return index; } } int size() const { return indexToWord.size(); } }; struct Node { // 最後に使った単語 int prevWordIndex; // オートマトン const PMA* automaton; // マッチ済み int numberOfMatches; Node(int prevWordIndex, const PMA* automaton, int numberOfMatches) : prevWordIndex(prevWordIndex), automaton(automaton), numberOfMatches(numberOfMatches) {} bool operator < (const Node& rh) const { return prevWordIndex != rh.prevWordIndex ? prevWordIndex < rh.prevWordIndex : automaton != rh.automaton ? automaton < rh.automaton : numberOfMatches < rh.numberOfMatches; } }; struct Uniquer { bool operator()(vector& rh) const { sort(ALL(rh)); rh.erase(unique(ALL(rh)), rh.end()); } }; int main() { std::ios::sync_with_stdio(false); for (int N, M, L; cin >> N >> M >> L && (N || M || L); ) { Dictionary dictionary; vector > connections(N * 2 + 1); const int indexRoot = dictionary.toIndex(""); REP(n, N) { string from, to; cin >> from >> to; const int indexFrom = dictionary.toIndex(from); const int indexTo = dictionary.toIndex(to); connections[indexRoot].push_back(indexFrom); connections[indexRoot].push_back(indexTo); connections[indexFrom].push_back(indexTo); } for_each(ALL(connections), Uniquer()); for (vector >::iterator it = connections.begin(), itEnd = connections.end(); it != itEnd; ++it) { sort(it->begin(), it->end()); it->erase(unique(it->begin(), it->end()), it->end()); } vector seasonWords; REP(l, L) { string seasonWord; cin >> seasonWord; seasonWords.push_back(seasonWord); } const PMA* root = buildPMA(seasonWords); const int numberOfWords = dictionary.size(); // [何文字目][最後に使った単語, オートマトン番号] = 個数 vector > dp(M + 1); dp[0][Node(0, root, 0)] = 1; REP(m, M) { map& prevNodes = dp[m]; for (map::iterator it = prevNodes.begin(), itEnd = prevNodes.end(); it != itEnd; ++it) { const Node& prevNode = it->first; const vector& dsts = connections[prevNode.prevWordIndex]; REP(dstIndex, dsts.size()) { const int nextWordIndex = dsts[dstIndex]; int nextMatched = prevNode.numberOfMatches; const PMA* pma = prevNode.automaton; const string& word = dictionary.toWord(nextWordIndex); if (m + (int)word.size() > M) { continue; } REP(letterIndex, word.size()) { const char ch = word[letterIndex]; while (!pma->next[ch]) { pma = pma->next[0]; } pma = pma->next[ch]; nextMatched += pma->accept.size(); if (nextMatched >= 2) { break; } } if (nextMatched >= 2) { continue; } int& r = dp[m + word.size()][Node(nextWordIndex, pma, nextMatched)]; r += it->second; r %= kMod; } } prevNodes.clear(); } // [何文字目][最後に使った単語][オートマトン番号][マッチ済み] int answer = 0; for (map::iterator it = dp[M].begin(), itEnd = dp[M].end(); it != itEnd; ++it) { if (it->first.numberOfMatches == 0) { continue; } answer += it->second; answer %= kMod; } cout << answer << endl; } }