QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#568914#9319. Bull FarmFangYifanWA 442ms40356kbC++174.5kb2024-09-16 19:13:182024-09-16 19:13:19

Judging History

你现在查看的是最新测评结果

  • [2024-09-16 19:13:19]
  • 评测
  • 测评结果:WA
  • 用时:442ms
  • 内存:40356kb
  • [2024-09-16 19:13:18]
  • 提交

answer

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

constexpr int N = 2e3 + 10;
constexpr int Q = 1e6 + 10;
int read() {
    char u, v;
    cin >> u >> v;
    return (u - 48) * 50 + (v - 48);
}
int f[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void merge(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx == fy) return;
    f[fx] = fy;
}
int n, m, q, ans[Q];
vector<array<int, 3>> qes[Q];
vector<pair<int, int>> add_edge[N];
vector<int> edge[N], scc_edge[N];
int step, top, scc_cnt;
int dfn[N], low[N], stk[N], instk[N], id[N];
void clear(int opt) {
    step = top = 0;
    memset(dfn, 0, sizeof(int) * (n + 2));
    if (!opt) for (int i = 1; i <= n; i++) edge[i].clear();
    for (int i = 1; i <= n; i++) scc_edge[i].clear();
}
void tarjan(int u) {
    dfn[u] = low[u] = ++step;
    stk[++top] = u;  // 节点 u 入栈
    instk[u] = true; // 标记 u 在栈中
    for (auto v : edge[u]) {
        if (dfn[v] == 0) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (instk[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        while (true) {
            int cur = stk[top--]; // 节点 cur 出栈
            instk[cur] = false;   // 节点 cur 出栈
            id[cur] = u;	      // 节点 cur 所在强连通分量中 根节点 u
            if (cur == u) break;
        }
    }
}
void solve() {
    clear(0);
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
        add_edge[i].clear();
        vector<int> p(n + 1), cnt(n + 1);
        for (int j = 1; j <= n; j++) {
            p[j] = read();
            // cerr << p[j] << " \n"[j == n];
            cnt[p[j]]++;
        }
        int two = -1, zero = -1, ok = true;
        for (int j = 1; j <= n; j++) {
            if (cnt[j] == 2) {
                if (two == -1) two = j;
                else ok = false;
            } else if (cnt[j] == 0) {
                if (zero == -1) zero = j;
                else ok = false;
            }
        }
        if (!ok) continue; // 该按钮对应的转移边不合法
        if (two == -1) {
            for (int j = 1; j <= n; j++) {
                // cerr << i << ' ' << j << ' ' << p[j] << "\n";
                add_edge[i].push_back({j, p[j]});
            }
        } else for (int j = 1; j <= n; j++) {
            if (cnt[p[j]] == 2) {
                // cerr << i << ' ' << j << ' ' << zero << "\n";
                add_edge[i].push_back({j, zero});
            }
        }
    }
    for (int i = 1; i <= q; i++) {
        int a = read(), b = read(), c = read();
        // cerr << a << ' ' << b << ' ' << c << "\n";
        qes[c].push_back({a, b, i});
    }
    for (int i = 1; i <= n; i++) f[i] = i;
    for (int c = 0; c <= m; c++) {
        // 加边
        for (auto [u, v] : add_edge[c]) {
            edge[find(u)].push_back(find(v));
            // cerr << c << ' ' << find(u) << ' ' << find(v) << '\n';
        }
        // 跑强连通分量缩点 tarjan 算法
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) tarjan(i);
        }
        set<pair<int, int>> st;
        for (int i = 1; i <= n; i++) {
            for (auto j : edge[i]) {
                int u = id[i], v = id[j];
                if (u != v && !st.count({u, v})) {
                    st.insert({u, v});
                    scc_edge[u].push_back(v);
                }
            }
        }
        // 将每个节点 i 合并到所在缩点集合 id[i] 中
        for (int i = 1; i <= n; i++) {
            // cerr << i << ' ' << id[i] << "\n";
            merge(i, id[i]);
            edge[i] = scc_edge[i];
        }
        // tarjan 缩点后,缩点后建图的拓扑序是 n ... 1
        vector<bitset<4>> dp(n + 1);
        for (int i = n; i >= 1; i--) {
            dp[i][i] = 1;
            for (auto j : edge[i]) {
                dp[j] |= dp[i];
            }
        }
        // for (int i = 1; i <= n; i++) {
        //     cerr << dp[i] << "\n";
        // }
        for (auto [a, b, qid] : qes[c]) {
            // cerr << a << ' ' << b << ' ' << c << ' ' << find(a) << ' ' << find(b) << ' ' << dp[find(b)][find(a)] << "\n";
            ans[qid] = dp[find(b)][find(a)];
        }
        clear(1);
    }
    for (int i = 1; i <= q; i++) cout << ans[i];
    cout << "\n";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt = 1;
    cin >> tt;
    while (tt--) {
        solve();
    }
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 27900kb

input:

2
5 2 4
0305040201
0404040404
030300
020500
050102
020501
6 2 4
030603010601
010203060504
030202
060402
050602
060401

output:

1011
0100

result:

ok 2 lines

Test #2:

score: 0
Accepted
time: 4ms
memory: 28964kb

input:

1
3 3 6
020202
030301
030201
020102
030203
010201
010303
020303
010202

output:

010101

result:

ok single line: '010101'

Test #3:

score: -100
Wrong Answer
time: 442ms
memory: 40356kb

input:

200
10 10 5000
01060:04020305080709
0103070:060204050908
09070503080401060:02
050308010204090:0607
03010502040607080:09
03080109020504060:07
06050:09040302080107
07080305010409060:02
030809010:0204060507
0:060908070201050304
060700
090:03
09080:
070405
010703
0:0100
080601
030600
070206
0:0:09
08040...

output:

011110001101101111111111111111111101111111110111011110110110111011010111111111111111111101111111111110111111110111111111111101111111111110111111111111111111110001100111111111111111111111111011101111111111111111111111111111111111111111011011110100111110111111110111111100111111101110111111111101111110...

result:

wrong answer 2nd lines differ - expected: '111111011101111011011111111111...1111110111111110111011110101111', found: '111111111101111111111111111111...1111111111111110111111111111111'