YC314A [ 20240704 CQYC省選模擬賽 T1 ] 士兵(solider)

cxqghzj發表於2024-07-04

題意

給定一張 \(n\) 個點 \(m\) 條邊的有向圖,每條邊上有一個字母。

\(q\) 次詢問,每次詢問 \(s \to t\) 中的最短迴文路徑的長度是多少。

\(n \le 10 ^ 3, m \le 10 ^ 5\)

Sol

區間 \(\text{dp}\),設 \(f_{i, j}\) 表示從 \(i\)\(j\) 的最短迴文路徑的長度。

每次列舉一條邊 \(l \to i\),以及 \(j \to r\),判斷兩條邊的字母是否相等,暴力轉移即可。

直接對於每個點跑一遍 \(\text{bfs}\),複雜度為 \(O(m ^ 2)\)

考慮最佳化,將一次過程拆成兩次。

\(g_{i, j, c}\) 表示從 \(i\)\(j\) 的最短迴文路徑,且最後一條邊為的字母為 \(c\)

對於一個狀態 \(f_{x, y}\),列舉一條出邊 \(y \to z\),轉移到 \(g_{x, z, c}\) 上。

這樣就變成了有兩種邊的 \(\text{bfs}\),考慮用兩個佇列來存,這樣每次取兩個佇列中 \(dis\) 較小的即可。

複雜度:\(O(nm + 26n ^ 2)\)

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <tuple>
#include <queue>
#include <vector>
#include <assert.h>
#define pii pair <int, int>
#define tupl tuple <int, int, char>
using namespace std;
#ifdef ONLINE_JUDGE

/* #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) */
/* char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; */

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

#define fi first
#define se second

const int N = 1e3 + 5, M = 1e5 + 5, inf = 1e9 + 7;

char strbuf[2];

array <array <vector <int>, 31>, N> G, T;

queue <pii> q1;
queue <tupl> q2;

array <array <int, N>, N> f;
array <array <pii, N>, N> pref;
array <array <array <int, 31>, N>, N> g;
array <array <array <pii, 31>, N>, N> preg;

void bfs(int n, int m) {
    while (!q1.empty() || !q2.empty()) {
        bool flg1 = q1.empty(), flg2 = q2.empty();
        int u1 = 0, u2 = 0, v1 = 0, v2 = 0, l1 = 0, l2 = 0, c = 0;
        if (!flg1) u1 = q1.front().fi, v1 = q1.front().se, l1 = f[u1][v1];
        if (!flg2) tie(u2, v2, c) = q2.front(), l2 = g[u1][v1][c];
        if (!flg1 && (flg2 || l1 <= l2)) {
            q1.pop();
            c = 0;
            for ( ; c < 26; c++) {
                for (auto k : G[v1][c]) {
 //                   if (v1 == 3 && c == 'm' - 'a')
 //                       cerr << u1 << endl;
                    if (~g[u1][k][c]) continue;
                    g[u1][k][c] = f[u1][v1] + 1;
                    preg[u1][k][c] = make_pair(v1, c);
                    q2.push(make_tuple(u1, k, c));
                }
            }
        }
        else {
            q2.pop();
            for (auto k : T[u2][c]) {
                if (~f[k][v2]) continue;
                f[k][v2] = g[u2][v2][c] + 1;
                pref[k][v2] = make_pair(u2, c);
                q1.push(make_pair(k, v2));
            }
        }
    }
}

array <int, M * 20> ans;

void print(int x, int y, int k, int l, int r) {
    if (x == y) return;
    if (k == -1) {
        ans[l] = pref[x][y].se;
        print(pref[x][y].fi, y, ans[l], l + 1, r);
    }
    else {
        ans[r] = preg[x][y][k].se;
        print(x, preg[x][y][k].fi, -1, l, r - 1);
    }
}

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read(), m = read(), tp = read();
    /* int n = read(), m = read(); */
    for (int i = 0; i <= n; i++) f[i].fill(-1);
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++) g[i][j].fill(-1);
    for (int i = 1; i <= n; i++)
        f[i][i] = 0, q1.push(make_pair(i, i));
    for (int i = 1; i <= m; i++) {
        int x = read(), y = read();
        scanf("%s", strbuf);
        G[x][strbuf[0] - 'a'].push_back(y), T[y][strbuf[0] - 'a'].push_back(x);
        q1.push(make_pair(x, y)), f[x][y] = 1, pref[x][y] = make_pair(x, strbuf[0] - 'a');
    }
    bfs(n, m);
 //   cerr << f[3][5] << endl;
    int q = read();
    while (q--) {
        int x = read(), y = read();
        write(f[x][y]), putchar(32);
       // assert(f[x][y] <= m);
        if (tp == 1 && ~f[x][y]) {
            print(x, y, -1, 1, f[x][y]);
            for (int i = 1; i <= f[x][y]; i++)
                putchar(ans[i] + 'a');
        }
        puts("");
    }
   /*
    int q = read(), x = read(); q--;
    while (q--) {
        int y = read();
        write(f[x][y]), putchar(32);
        assert(f[x][y] <= m);
        if (~f[x][y]) {
            print(x, y, -1, 1, f[x][y]);
            for (int i = 1; i <= f[x][y]; i++)
                putchar(ans[i] + 'a');
        }
        puts("");
        x = y;
    }
    */
    return 0;
}

相關文章