CodeForces 1500C Matrix Sorting
做了好久。怎么会是呢。
题目的操作可以看成,求出一些关键字,使得 \(B\) 矩阵的行是由 \(A\) 按照这些第 \(1\) 关键字、第 \(2\) 关键字一直到第 \(k\) 关键字,最后还有一个原来所在行下标的关键字,从小到大排序。
肯定是从排好序的 \(B\) 矩阵入手。首先任意找到一个在 \(B\) 矩阵中已经排好序的列。然后把这一列极长的相等段拎出来,把 \([1, n]\) 分成了若干个区间 \([l_1, r_1], [l_2, r_2], \ldots, [l_k, r_k]\)。发现这是一个递归的过程,我们还要找到一个之前没选过的列,在这些区间分别是升序的。然后可以把这些区间分成一些更小的区间。可以把区间存下来,一轮一轮地判断。
终止条件就是,\([l_1, r_1] \sim [l_k, r_k]\) 都是 \(A\) 矩阵的子序列(因为最后一个排序的关键字是行的下标)。这个可以对每行哈希,然后建子序列自动机判断即可。
但是兴冲冲的写了一发,T 了。发现枚举每一列再判断在这些区间是否分别升序会使得复杂度退化至 \(O(n^3)\)。想起来有个东西叫 bitset。可以把第 \(i\) 行 \(B_{i, j} < B_{i + 1, j}\) 的所有列下标 \(j\) 开个 bitset 存起来,那么得到所有升序的行,只需把 \([l_1, r_1 - 1] \sim [l_k, r_k - 1]\) 的 bitset 与起来就行了。时间复杂度变为 \(O(\frac{n^3}{\omega})\)。
子序列自动机部分若开 vector 存位置然后每次二分就是 \(O(n^2 \log n)\)。但是也能过。跑得还不慢。
code
// Problem: C. Matrix Sorting
// Contest: Codeforces - Codeforces Round 707 (Div. 1, based on Moscow Open Olympiad in Informatics)
// URL: https://codeforces.com/problemset/problem/1500/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 1510;
const ll base = 131, mod1 = 998244853, mod2 = 1145141999;
int n, m, a[maxn][maxn], b[maxn][maxn], tot, c[maxn];
ll f1[maxn], g1[maxn], f2[maxn], g2[maxn];
bitset<maxn> f[maxn], g;
pii lsh[maxn];
vector<int> vc[maxn];
bool vis[maxn];
inline bool check(int l, int r) {
int i = 1;
for (int j = l; j <= r; ++j) {
auto it = lower_bound(vc[c[j]].begin(), vc[c[j]].end(), i);
if (it == vc[c[j]].end()) {
return 0;
}
i = *it + 1;
}
return 1;
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &a[i][j]);
f1[i] = (f1[i] * base + a[i][j]) % mod1;
f2[i] = (f2[i] * base + a[i][j]) % mod2;
}
lsh[++tot] = mkp(f1[i], f2[i]);
}
sort(lsh + 1, lsh + tot + 1);
tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
for (int i = 1; i <= n; ++i) {
vc[lower_bound(lsh + 1, lsh + tot + 1, mkp(f1[i], f2[i])) - lsh].pb(i);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &b[i][j]);
g1[i] = (g1[i] * base + b[i][j]) % mod1;
g2[i] = (g2[i] * base + b[i][j]) % mod2;
}
c[i] = lower_bound(lsh + 1, lsh + tot + 1, mkp(g1[i], g2[i])) - lsh;
if (lsh[c[i]] != mkp(g1[i], g2[i])) {
puts("-1");
return;
}
}
for (int i = 1; i < n; ++i) {
for (int j = 1; j <= m; ++j) {
if (b[i][j] <= b[i + 1][j]) {
f[i].set(j);
}
}
}
vector<int> ans;
vector<pii> vc;
vc.pb(1, n);
while (1) {
bool fl = 1;
for (pii p : vc) {
if (!check(p.fst, p.scd)) {
fl = 0;
break;
}
}
if (fl) {
printf("%d\n", (int)ans.size());
reverse(ans.begin(), ans.end());
for (int i : ans) {
printf("%d ", i);
}
return;
}
bool t = 0;
g.set();
for (pii p : vc) {
for (int j = p.fst; j < p.scd; ++j) {
g &= f[j];
}
}
for (int i = 1; i <= m; ++i) {
if (vis[i] || !g.test(i)) {
continue;
}
ans.pb(i);
t = 1;
vis[i] = 1;
vector<pii> nv;
for (pii p : vc) {
int l = p.fst, r = p.scd;
for (int j = l, k = l; j <= r; j = (++k)) {
while (k < r && b[k + 1][i] == b[j][i]) {
++k;
}
nv.pb(j, k);
}
}
vc = nv;
break;
}
if (!t) {
puts("-1");
return;
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}