C. AquaMoon and Permutations

目录

1.Problem

2.Input

3.Output

4.Examples

4.1input

4.2output

5.Code

6.Conclusion


1.Problem

Cirno has prepared nn arrays of length nn each. Each array is a permutation of nn integers from 11 to nn. These arrays are special: for all 1≤i≤n1≤i≤n, if we take the ii-th element of each array and form another array of length nn with these elements, the resultant array is also a permutation of nn integers from 11 to nn. In the other words, if you put these nn arrays under each other to form a matrix with nn rows and nn columns, this matrix is a Latin square.

Afterwards, Cirno added additional nn arrays, each array is a permutation of nn integers from 11 to nn. For all 1≤i≤n1≤i≤n, there exists at least one position 1≤k≤n1≤k≤n, such that for the ii-th array and the (n+i)(n+i)-th array, the kk-th element of both arrays is the same. Notice that the arrays indexed from n+1n+1 to 2n2n don't have to form a Latin square.

Also, Cirno made sure that for all 2n2n arrays, no two arrays are completely equal, i. e. for all pair of indices 1≤i<j≤2n1≤i<j≤2n, there exists at least one position 1≤k≤n1≤k≤n, such that the kk-th elements of the ii-th and jj-th array are different.

Finally, Cirno arbitrarily changed the order of 2n2n arrays.

AquaMoon calls a subset of all 2n2n arrays of size nn good if these arrays from a Latin square.

AquaMoon wants to know how many good subsets exist. Because this number may be particularly large, find it modulo 998244353998244353. Also, she wants to find any good subset. Can you help her?

2.Input

The input consists of multiple test cases. The first line contains a single integer tt (1≤t≤1001≤t≤100) — the number of test cases.

The first line of each test case contains a single integer nn (5≤n≤5005≤n≤500).

Then 2n2n lines followed. The ii-th of these lines contains nn integers, representing the ii-th array.

It is guaranteed, that the sum of nn over all test cases does not exceed 500500.

3.Output

For each test case print two lines.

In the first line, print the number of good subsets by modulo 998244353998244353.

In the second line, print nn indices from 11 to 2n2n — indices of the nn arrays that form a good subset (you can print them in any order). If there are several possible answers — print any of them.

4.Examples

4.1input

3
7
1 2 3 4 5 6 7
2 3 4 5 6 7 1
3 4 5 6 7 1 2
4 5 6 7 1 2 3
5 6 7 1 2 3 4
6 7 1 2 3 4 5
7 1 2 3 4 5 6
1 2 3 4 5 7 6
1 3 4 5 6 7 2
1 4 5 6 7 3 2
1 5 6 7 4 2 3
1 6 7 5 2 3 4
1 7 6 2 3 4 5
1 7 2 3 4 5 6
5
4 5 1 2 3
3 5 2 4 1
1 2 3 4 5
5 2 4 1 3
3 4 5 1 2
2 3 4 5 1
1 3 5 2 4
4 1 3 5 2
2 4 1 3 5
5 1 2 3 4
6
2 3 4 5 6 1
3 1 2 6 4 5
6 1 2 3 4 5
5 6 1 3 2 4
4 3 6 5 2 1
5 6 1 2 3 4
4 5 6 1 2 3
3 4 5 6 1 2
1 2 3 4 5 6
2 5 4 1 6 3
3 2 5 4 1 6
1 4 3 6 5 2

4.2output

1
1 2 3 4 5 6 7
2
1 3 5 6 10
4
1 3 6 7 8 9
 

5.Code

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

const int MOD = 998244353;
const int MAXN = 505;
const int MAXM = 1005;

vector<int> g[MAXM];
int col[MAXM], vis[MAXM], hv[MAXN][MAXN], b[MAXN][MAXN], c[MAXN][MAXN];
int a[MAXM][MAXN];
queue<int> q;

template <typename T>
bool updateMax(T& x, T y) {
    if (x < y) {
        x = y;
        return true;
    }
    return false;
}

template <typename T>
bool updateMin(T& x, T y) {
    if (x > y) {
        x = y;
        return true;
    }
    return false;
}

int readint() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

void addedge(int x, int y) {
    g[x].push_back(y);
    g[y].push_back(x);
}

void dfs(int u, int color) {
    col[u] = color;
    for (int v : g[u]) {
        if (col[v] == -1) {
            dfs(v, color ^ 1);
        }
    }
}

void erase(int id) {
    if (vis[id]) return;
    for (int i = 1; i <= n; ++i) {
        b[i][a[id][i]]--;
        c[i][a[id][i]] -= id;
        if (b[i][a[id][i]] == 1 && !hv[i][a[id][i]]) {
            q.push(i);
        }
    }
    vis[id] = 1;
}

int main() {
    int T = readint();
    while (T--) {
        int n = readint();
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                b[i][j] = c[i][j] = 0;
                hv[i][j] = false;
            }
            g[i].clear();
        }
        for (int i = 1; i <= n + n; ++i) {
            vis[i] = false;
            col[i] = -1;
        }
        for (int i = 1; i <= n + n; ++i) {
            for (int j = 1; j <= n; ++j) {
                a[i][j] = readint();
                b[j][a[i][j]]++;
                c[j][a[i][j]] += i;
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (b[i][j] == 1) {
                    q.push(i);
                }
            }
        }
        int cnt = 0;
        while (!q.empty()) {
            int t = q.front();
            q.pop();
            int pl = c[t][a[t]];
            if (!pl || vis[pl]) continue;
            vis[pl] = 1;
            for (int i = 1; i <= n; ++i) {
                b[i][a[pl][i]]--;
                c[i][a[pl][i]] -= pl;
                if (b[i][a[pl][i]] == 1 && !hv[i][a[pl][i]]) {
                    q.push(i);
                }
            }
        }
        for (int i = 1; i <= n + n; ++i) {
            if (!vis[i]) {
                if (col[i] < 0) {
                    dfs(i, 0);
                }
            }
        }
        long long ans = 1LL << cnt;
        cout << ans << endl;
        vector<int> res;
        for (int i = 1; i <= n + n; ++i) {
            if (vis[i]) {
                res.push_back(i);
            }
        }
        for (int i = 1; i <= n + n; ++i) {
            if (col[i] == 0) {
                res.push_back(i);
            }
        }
        sort(res.begin(), res.end());
        for (int r : res) {
            cout << r << ' ';
        }
        cout << endl;
    }
    return 0;
}

6.Conclusion

        这段代码的核心逻辑是解决一个图论问题,其中涉及到染色、删除操作、计数和输出等步骤。下面逐步解释代码的核心逻辑:

1.首先定义了一些常量和全局变量,包括MOD(取模数),MAXN(最大节点数),MAXM(最大边数),以及用于存储图、染色、访问状态、数值统计的数组和队列等。
2.定义了两个模板函数 updateMax 和 updateMin,用于更新变量的最大值和最小值。
3.定义了一个函数 readint,用于从输入流中读取一个整数。
4.定义了一个函数 addedge,用于向图中添加边。
5.定义了一个递归函数 dfs,用于对图进行深度优先搜索,并进行节点的染色(只有两种颜色)。其中,传入参数 u 代表当前节点,color 代表当前节点的颜色。
6.定义了一个函数 erase,用于删除某个边。具体操作是将统计数组中对应的数值减小,如果减小到1且对应节点没有访问过,则将节点加入队列中。同时,将该边的状态标记为已删除。
7.main 函数通过读取输入,进行图的初始化操作。主要步骤包括读取测试用例数量,读取节点数量,初始化相关数组,读取图的边权值等。
8.在初始化完毕后,根据题目要求将只出现一次的节点加入队列中。
9.接下来,利用广度优先搜索思想进行边的删除操作。通过对队列进行遍历,依次删除边,并更新相关统计数组和状态。
10.最后,统计未删除边的个数,并输出结果。然后将已删除边和染色节点分别加入结果数组中,最后按顺序输出结果。

        总体来说,这段代码的核心逻辑是解决一个图论问题,通过染色、删除操作、广度优先搜索、统计和排序等步骤,计算未删除边的个数,并输出结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向阳而生__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值