QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#865428#9731. Fuzzy Rankingsurenjamts#WA 29ms3712kbC++206.3kb2025-01-21 18:28:382025-01-21 18:28:38

Judging History

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

  • [2025-01-21 18:28:38]
  • 评测
  • 测评结果:WA
  • 用时:29ms
  • 内存:3712kb
  • [2025-01-21 18:28:38]
  • 提交

answer

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

using ll = long long;
#define int long long

// Utility macros/functions
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define put(x) cout << (x) << '\n'

// Kosaraju components
void dfs1(int node, vector<vector<int>>& adj, vector<bool>& visited, stack<int>& finishOrder) {
    visited[node] = true;
    for (int neighbor : adj[node]) {
        if (!visited[neighbor]) {
            dfs1(neighbor, adj, visited, finishOrder);
        }
    }
    finishOrder.push(node);
}

void dfs2(int node, vector<vector<int>>& radj, vector<bool>& visited, vector<int>& component) {
    visited[node] = true;
    component.push_back(node);
    for (int neighbor : radj[node]) {
        if (!visited[neighbor]) {
            dfs2(neighbor, radj, visited, component);
        }
    }
}

vector<vector<int>> kosaraju(int n, vector<vector<int>>& edges) {
    // 1) Build adjacency
    vector<vector<int>> adj(n);
    for (auto &e : edges) {
        adj[e[0]].push_back(e[1]);
    }

    // 2) DFS on original graph to get finishing order
    vector<bool> visited(n, false);
    stack<int> finishOrder;
    for (int i = 0; i < n; i++){
        if(!visited[i]) dfs1(i, adj, visited, finishOrder);
    }

    // 3) Reverse graph
    vector<vector<int>> radj(n);
    for (auto &e : edges){
        radj[e[1]].push_back(e[0]);
    }

    // 4) DFS on reversed graph using finish order
    fill(visited.begin(), visited.end(), false);
    vector<vector<int>> scc;
    while(!finishOrder.empty()){
        int node = finishOrder.top();
        finishOrder.pop();
        if(!visited[node]){
            vector<int> component;
            dfs2(node, radj, visited, component);
            scc.push_back(component);
        }
    }
    return scc;
}

void solve() {
    int n, k, q;
    cin >> n >> k >> q;

    // Read all edges from k lists of size n
    vector<vector<int>> edges;
    edges.reserve(k * (n - 1)); // optional optimization

    // Read k permutations, zero-based
    vector<vector<int>> lists(k, vector<int>(n));
    for (int i = 0; i < k; i++) {
        for (int j = 0; j < n; j++) {
            cin >> lists[i][j];
            lists[i][j]--;
            if(j > 0) {
                edges.push_back({lists[i][j - 1], lists[i][j]});
            }
        }
    }

    // Kosaraju -> component IDs
    auto comps = kosaraju(n, edges);
    vector<int> compID(n);
    for (int i = 0; i < (int)comps.size(); i++) {
        for (int v : comps[i]) {
            compID[v] = i + 1; // 1-based
        }
    }

    // Build 'ends[i]' and 'p[i]' for each of the k lists
    // 'ends[i]' = boundaries where compID changes
    // 'p[i]' = partial sum array of something (the sum of intervals, presumably)
    vector<vector<int>> ends(k), p(k, vector<int>(n, 0));

    for (int i = 0; i < k; i++) {
        ll sum = 0;
        int startIdx = 0;             // start of the current interval
        int prevComp = compID[lists[i][0]];

        for (int j = 1; j < n; j++) {
            int curComp = compID[lists[i][j]];
            // If compID changes, we close off the interval [startIdx..j-1]
            if (curComp != prevComp) {
                ll len = j - startIdx; // length of this interval
                // sum of pairs: len*(len-1)/2
                sum += len * (len - 1) / 2;
                p[i][j-1] = sum;      // store partial sum up to j-1
                ends[i].push_back(j-1);

                startIdx = j;         // start new interval
                prevComp = curComp;
            }
        }
        // Close off final interval [startIdx..n-1]
        ll lastLen = n - startIdx;
        sum += lastLen * (lastLen - 1) / 2;
        p[i][n - 1] = sum;
        ends[i].push_back(n - 1);
    }

    // Process queries
    ll prevAns = 0;
    while (q--) {
        ll id, l, r;
        cin >> id >> l >> r;

        // decode with previous answer
        id = (id + prevAns) % k;
        l  = (l  + prevAns) % n;
        r  = (r  + prevAns) % n;

        // If they're in the same SCC, easy
        if (compID[l] == compID[r]) {
            ll length = (r - l + 1);
            // If r >= l, length is (r-l+1). If r < l, do you wrap or is it invalid?
            // For now, assume r >= l from the problem statement.
            ll ans = length * (length - 1) / 2;
            cout << ans << "\n";
            prevAns = ans;
            continue;
        }

        // Otherwise, we do partial sums:
        ll ans = 0;

        // --- Compute L boundary:
        auto itL = std::lower_bound(ends[id].begin(), ends[id].end(), l);
        ll L;
        if (itL == ends[id].end()) {
            // l is bigger than any boundary => use the last boundary
            L = ends[id].back();
        } else {
            L = *itL;
        }

        // --- Compute R boundary:
        auto itR = std::lower_bound(ends[id].begin(), ends[id].end(), r);
        ll R;
        if (itR == ends[id].begin()) {
            // r <= ends[id].front()
            R = ends[id].front();
        } else {
            // Move one step back
            --itR;
            R = *itR;
        }

        // Interval piece from [l..L]
        // sum of pairs = (len*(len-1))/2
        ll lenLeft = (L >= l) ? (L - l + 1) : 0;
        ans += lenLeft * (lenLeft - 1) / 2;

        // Interval piece from [R..r]
        ll lenRight = (r > R) ? (r - R) : 0;
        ans += lenRight * (lenRight - 1) / 2;

        // The middle portion is p[id][R] - p[id][L], but only if R >= L
        // If R < L, that means there's no actual "middle" to add.
        if (R >= L) {
            ans += p[id][R] - ((L < 0) ? 0 : p[id][L]);
            // Because p[id][x] is a partial sum "up to index x."
            // If you originally stored partial sums differently, adjust accordingly.
            // In your code, you're using p[id][R] - p[id][L], but that might not handle L=0 properly.
        }

       // cout << L << ' ' <<  R << endl;
        //cout << lenLeft << ' ' << lenRight << endl;

        cout << ans << "\n";
        prevAns = ans;
    }
}

int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3712kb

input:

2
5 2 2
1 2 3 4 5
5 4 3 2 1
1 0 2
1 2 1
5 3 3
1 2 3 4 5
1 3 2 4 5
1 2 3 5 4
0 0 2
0 2 3
1 0 3

output:

3
10
1
1
2

result:

ok 5 lines

Test #2:

score: -100
Wrong Answer
time: 29ms
memory: 3712kb

input:

2000
10 10 10
4 5 3 6 8 9 2 1 7 10
4 5 6 3 8 9 1 2 10 7
5 4 3 6 8 9 1 2 7 10
4 5 6 3 8 9 1 2 7 10
4 5 3 6 8 9 2 1 10 7
4 5 6 3 8 9 1 2 10 7
5 4 6 3 8 9 1 2 7 10
5 4 6 3 8 9 1 2 10 7
4 5 6 3 8 9 2 1 7 10
5 4 3 6 8 9 2 1 10 7
3 1 6
5 7 8
0 2 3
7 9 9
2 1 9
6 1 6
7 2 3
0 0 4
1 8 1
1 8 7
10 10 10
9 10 5 ...

output:

1
2
0
0
3
2
0
2
2
4
4
0
1
4
0
1
2
4
4
3
1
6
28
0
0
10
10
6
6
15
0
3
15
15
18
3
1
1
6
13
1
12
4
1
6
2
1
3
4
1
1
3
2
4
0
3
4
4
4
4
0
0
1
1
2
0
0
1
2
1
1
0
0
3
0
0
0
4
4
1
3
6
16
16
0
11
16
1
4
21
2
3
3
0
1
1
1
2
1
1
0
0
0
0
0
0
0
0
0
0
1
0
0
28
3
0
3
4
0
0
0
0
0
0
0
0
0
0
0
0
3
0
0
1
3
1
0
0
3
21
9
4
...

result:

wrong answer 2nd lines differ - expected: '1', found: '2'