// 1. 10 generacji ręcznie (dla symboli od 1 do 500):
// a) czy jest match w środku
// b) jakie prefixy patternu pasują na koniec (max prefix)
// c) sakie suffixy patternu pasują na początek (max suffix)
// 2. Kiedy osiągany jest dany symbol po raz pierwszy?
// 3. Kiedy osiągana jest dana para po raz pierwszy?
// 4. Które kombinacje prefix-suffix (1b, 1c) dają match?
//
// No i teraz:
// - 2+1a (500 x 11)
// - 4+3 (500 x 500 x 11)
//
// Czasy generowania:
// 1a) 1001 x 11 x (500 + 1000)
// 1b) czytamy z tabelek z 1a
// 1c) czytamy z tabelek z 1a
// 2+3. BFS (500x500 + 1000)
// 4. 1000x1000
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
queue<pair<int, int> > q;
vector<vector<int> > time;
void Enqueue(const int l, const int r, const int t) {
if (time[l][r] >= 0) return;
time[l][r] = t;
q.push(make_pair(l, r));
}
// http://stackoverflow.com/questions/13792118/kmp-prefix-table
template <typename Iterator>
vector<int> PrefixFunction(const Iterator begin, const Iterator end) {
const int size = end - begin;
vector<int> p(size);
int j = 0;
for (int i = 1; i < size; ++i) {
while (j > 0 && *(begin + j) != *(begin + i)) j = p[j - 1];
if (*(begin + j) == *(begin + i)) ++j;
p[i] = j;
}
return p;
}
int main() {
int n;
int m;
scanf("%d%d", &n, &m);
vector<vector<int> > h(n);
for (int i = 0; i < n; ++i) {
int l;
scanf("%d", &l);
h[i].resize(l);
for (int j = 0; j < l; ++j) {
scanf("%d", &h[i][j]);
--h[i][j];
}
}
vector<int> s(m);
for (int i = 0; i < m; ++i) {
scanf("%d", &s[i]);
--s[i];
}
vector<vector<vector<int> > > transition(11, vector<vector<int> >(n, vector<int>(m + 1, 0)));
// Identycznosc.
for (int i = 0; i <= 10; ++i) for (int j = 0; j < n; ++j) for (int k = 0; k <= m; ++k) transition[i][j][k] = k;
// Nic nie pasuje...
for (int j = 0; j < n; ++j) for (int k = 0; k < m; ++k) transition[0][j][k] = 0;
// ...z wyjątkiem symboli wzorca.
for (int k = 0; k < m; ++k) transition[0][s[k]][k] = k + 1;
// Wypelnienie dynamiczne reszty, co konczy krok 1a.
for (int i = 0; i < 10; ++i) for (int j = 0; j < n; ++j) for (int k = 0; k <= m; ++k) for (int l = 0; l < h[j].size(); ++l) transition[i + 1][j][k] = transition[i][h[j][l]][transition[i + 1][j][k]];
// 1b+c.
vector<vector<int> > best_prefix(11, vector<int>(n, 0));
vector<vector<int> > best_suffix(11, vector<int>(n + 1, m));
for (int i = 0; i <= 10; ++i) for (int j = 0; j < n; ++j) {
best_prefix[i][j] = transition[i][j][0];
for (int k = m; k >= 0; --k) if (transition[i][j][k] == m) best_suffix[i][j] = k;
}
// 2+3.
time.resize(n, vector<int>(n + 1, -1));
Enqueue(0, n, 0);
while (!q.empty()) {
const pair<int, int> p = q.front();
const int l = p.first;
const int r = p.second;
const int t = time[l][r];
q.pop();
if (r == n) {
for (int i = 0; i < h[l].size(); ++i) {
Enqueue(h[l][i], n, t + 1);
if (i) Enqueue(h[l][i - 1], h[l][i], t + 1);
}
} else {
Enqueue(h[l].back(), h[r][0], t + 1);
}
}
// 4.
vector<vector<bool> > fit(m + 1, vector<bool>(m + 1, false));
for (int i = 0; i <= m; ++i) fit[i][i] = true;
{
const vector<int> p = PrefixFunction(s.begin(), s.end());
for (int i = 1; i <= m; ++i) for (int j = 0; j <= m; ++j) if (fit[p[i - 1]][j]) fit[i][j] = true;
}
{
const vector<int> p = PrefixFunction(s.rbegin(), s.rend());
for (int i = 0; i <= m; ++i) for (int j = m - 1; j >= 0; --j) if (fit[i][m - p[m - j - 1]]) fit[i][j] = true;
}
// Wynik.
int ret = -1;
for (int i = 0; i < n; ++i) for (int j = 0; j <= n; ++j) if (time[i][j] != -1) for (int k = 0; k <= 10; ++k) if (fit[best_prefix[k][i]][best_suffix[k][j]]) {
if (ret == -1 || time[i][j] + k < ret) ret = time[i][j] + k;
break;
}
printf("%d\n", ret + 1);
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | // 1. 10 generacji ręcznie (dla symboli od 1 do 500): // a) czy jest match w środku // b) jakie prefixy patternu pasują na koniec (max prefix) // c) sakie suffixy patternu pasują na początek (max suffix) // 2. Kiedy osiągany jest dany symbol po raz pierwszy? // 3. Kiedy osiągana jest dana para po raz pierwszy? // 4. Które kombinacje prefix-suffix (1b, 1c) dają match? // // No i teraz: // - 2+1a (500 x 11) // - 4+3 (500 x 500 x 11) // // Czasy generowania: // 1a) 1001 x 11 x (500 + 1000) // 1b) czytamy z tabelek z 1a // 1c) czytamy z tabelek z 1a // 2+3. BFS (500x500 + 1000) // 4. 1000x1000 #include <cstdio> #include <queue> #include <vector> using namespace std; queue<pair<int, int> > q; vector<vector<int> > time; void Enqueue(const int l, const int r, const int t) { if (time[l][r] >= 0) return; time[l][r] = t; q.push(make_pair(l, r)); } // http://stackoverflow.com/questions/13792118/kmp-prefix-table template <typename Iterator> vector<int> PrefixFunction(const Iterator begin, const Iterator end) { const int size = end - begin; vector<int> p(size); int j = 0; for (int i = 1; i < size; ++i) { while (j > 0 && *(begin + j) != *(begin + i)) j = p[j - 1]; if (*(begin + j) == *(begin + i)) ++j; p[i] = j; } return p; } int main() { int n; int m; scanf("%d%d", &n, &m); vector<vector<int> > h(n); for (int i = 0; i < n; ++i) { int l; scanf("%d", &l); h[i].resize(l); for (int j = 0; j < l; ++j) { scanf("%d", &h[i][j]); --h[i][j]; } } vector<int> s(m); for (int i = 0; i < m; ++i) { scanf("%d", &s[i]); --s[i]; } vector<vector<vector<int> > > transition(11, vector<vector<int> >(n, vector<int>(m + 1, 0))); // Identycznosc. for (int i = 0; i <= 10; ++i) for (int j = 0; j < n; ++j) for (int k = 0; k <= m; ++k) transition[i][j][k] = k; // Nic nie pasuje... for (int j = 0; j < n; ++j) for (int k = 0; k < m; ++k) transition[0][j][k] = 0; // ...z wyjątkiem symboli wzorca. for (int k = 0; k < m; ++k) transition[0][s[k]][k] = k + 1; // Wypelnienie dynamiczne reszty, co konczy krok 1a. for (int i = 0; i < 10; ++i) for (int j = 0; j < n; ++j) for (int k = 0; k <= m; ++k) for (int l = 0; l < h[j].size(); ++l) transition[i + 1][j][k] = transition[i][h[j][l]][transition[i + 1][j][k]]; // 1b+c. vector<vector<int> > best_prefix(11, vector<int>(n, 0)); vector<vector<int> > best_suffix(11, vector<int>(n + 1, m)); for (int i = 0; i <= 10; ++i) for (int j = 0; j < n; ++j) { best_prefix[i][j] = transition[i][j][0]; for (int k = m; k >= 0; --k) if (transition[i][j][k] == m) best_suffix[i][j] = k; } // 2+3. time.resize(n, vector<int>(n + 1, -1)); Enqueue(0, n, 0); while (!q.empty()) { const pair<int, int> p = q.front(); const int l = p.first; const int r = p.second; const int t = time[l][r]; q.pop(); if (r == n) { for (int i = 0; i < h[l].size(); ++i) { Enqueue(h[l][i], n, t + 1); if (i) Enqueue(h[l][i - 1], h[l][i], t + 1); } } else { Enqueue(h[l].back(), h[r][0], t + 1); } } // 4. vector<vector<bool> > fit(m + 1, vector<bool>(m + 1, false)); for (int i = 0; i <= m; ++i) fit[i][i] = true; { const vector<int> p = PrefixFunction(s.begin(), s.end()); for (int i = 1; i <= m; ++i) for (int j = 0; j <= m; ++j) if (fit[p[i - 1]][j]) fit[i][j] = true; } { const vector<int> p = PrefixFunction(s.rbegin(), s.rend()); for (int i = 0; i <= m; ++i) for (int j = m - 1; j >= 0; --j) if (fit[i][m - p[m - j - 1]]) fit[i][j] = true; } // Wynik. int ret = -1; for (int i = 0; i < n; ++i) for (int j = 0; j <= n; ++j) if (time[i][j] != -1) for (int k = 0; k <= 10; ++k) if (fit[best_prefix[k][i]][best_suffix[k][j]]) { if (ret == -1 || time[i][j] + k < ret) ret = time[i][j] + k; break; } printf("%d\n", ret + 1); return 0; } |
English