• CF1500C Matrix Sorting


    考虑最后一个操作,必然使得在被操作的这一列不同元素满足 (B) 矩阵中的相对位置。

    倒退到前面的操作,必然是让那些在最后一次被操作的列中,对于相同元素的相对关系的调整。

    发现关系过于复杂,使用图论建模,现在是要从矩阵 (B ightarrow A)

    由于每次只需要考虑 (B) 中相邻两行的顺序就可以确定整个矩阵行的顺序,所以只需考虑上下相邻的元素就可以确定操作和行间的关系。

    所以可以建立一个包含(相邻两行关系满足)和(操作)的点,那么边自然表示从后往前的操作顺序。

    由于是从后往前,所以执行一次操作的前提是将会被这次操作打乱的行之间的关系在正向操作时,后面的操作可以将其排成正确的顺序。

    两行之间的关系的点被经过的前提比较简单,就是有一次操作能使得这个关系合法即可。

    考虑图中边的意义,发现只有两行之间关系操作之间有边,那么有两类边,一类是表示关系已经满足,可以使用操作,另一类是表示这次操作可以使得一个关系满足,只要比较 (B_{i, j})(B_{i + 1, j}) 之间的大小关系就能确定边的方向。

    最后一个问题就是原来 (A) 矩阵中每行之间的相对位置,由于整个对于矩阵行的排序本质上就是一个基数排序,所以直接在 (B) 矩阵中加上一列,表示这一行在原来 (A) 矩阵中的相对位置。

    根据上述的含义,在这个图中,没有入度的操作点是起点,所有(k) 操作打乱的行之间的关系都满足后的 (k) 操作点可以通过,所有被任意一个操作满足的两行关系节点可以通过。

    可以感知到每一种操作只会被操作一次,所以 (5000) 次是很宽松的。

    接下来处理无解情况,只有两种,一种是 (A)(B) 矩阵不能通过任意改变行的顺序变得相同,另一种是怎么操作都无法使得 (B) 矩阵中加上的一列满足要求。

    时间复杂度 (mathcal O (n imes m))

    #include <bits/stdc++.h>
    #define forn(i,s,t) for(register int i=(s); i<=(t); ++i)
    #define form(i,s,t) for(register int i=(s); i>=(t); --i)
    #define rep(i,s,t) for(register int i=(s); i<(t); ++i)
    #define IT(u) for(register int i=G[u]; i; i=E[i].nxt)
    using namespace std;
    typedef unsigned long long u64;
    const int N = 1504;
    const int Md1 = 1e9 + 7, Md2 = 1e9 + 9;
    const int Bs1 = 114514, Bs2 = 1919810, SZ = (1 << 19) - 1;
    struct Lst {
    	u64 dir; int nxt, cnt; vector<int> pos;
    	Lst() {}
    	Lst(u64 _d, int _n, int _c, int _p) : dir(_d), nxt(_n), cnt(_c) {pos.reserve(10), pos.push_back(_p);}
    } ;
    struct Hash_table {
    	Lst E[1 << 19]; int G[1 << 19], cnt;
    	inline void Add(int u, u64 v, int p) {E[++cnt] = Lst(v, G[u], 1, p); G[u] = cnt;}
    	inline int Ins(u64 s, int pp) {
    		u64 t = s & SZ;
    		if(!G[t]) return Add(t, s, pp), 1;
    		IT(t) if(E[i].dir == s) return E[i].pos.push_back(pp), ++E[i].cnt;
    		return Add(t, s, pp), 1;
    	}
    	inline int Fnd(u64 s, int pp) {
    		u64 t = s & SZ;
    		IT(t) if(E[i].dir == s) {
    			if(E[i].pos.size() <= pp) return E[i].pos[pp - 1];
    			else return -1;
    		}
    		return -1;
    	}
    	inline int Srh(u64 s) {
    		u64 t = s & SZ;
    		if(!G[t]) return -1;
    		IT(t) if(E[i].dir == s) return E[i].cnt;
    		return -1;
    	}
    } At, Bt;
    struct LL {
    	int dir, nxt;
    	LL() {}
    	LL(int _d, int _n) : dir(_d), nxt(_n) {}
    } E[N * N << 1]; 
    int G[N << 1], cnt;
    inline void Add(int u, int v) {E[++cnt] = LL(v, G[u]), G[u] = cnt;}
    int n, m, a[N][N], b[N][N], d[N + N]; u64 Lhs[N], Rhs[N]; bool vis[N + N];
    vector<int> res;
    int main() {
    	scanf("%d%d", &n, &m);
    	forn(i,1,n) {
    		u64 Lt = 0, Rt = 0;
    		forn(j,1,m) {
    			scanf("%d", a[i] + j);
    			Lt = (1ll * Lt * Bs1 %Md1 + a[i][j]) %Md1;
    			Rt = (1ll * Rt * Bs2 %Md2 + a[i][j]) %Md2;
    		}
    		Lt = Lt << 32 | Rt;
    		Lt ^= Lt << 14, Lt ^= Lt >> 16, Lt ^= Lt << 7;
    		At.Ins(Lhs[i] = Lt, i);
    	}
    	forn(i,1,n) {
    		u64 Lt = 0, Rt = 0;
    		forn(j,1,m) {
    			scanf("%d", b[i] + j);
    			Lt = (1ll * Lt * Bs1 %Md1 + b[i][j]) %Md1;
    			Rt = (1ll * Rt * Bs2 %Md2 + b[i][j]) %Md2;
    		}
    		Lt = Lt << 32 | Rt;
    		Lt ^= Lt << 14, Lt ^= Lt >> 16, Lt ^= Lt << 7;
    		b[i][m + 1] = At.Fnd(Lt, Bt.Ins(Rhs[i] = Lt, i));
    	}
    	forn(i,1,n) if(At.Srh(Lhs[i]) != Bt.Srh(Lhs[i])) return puts("-1"), 0;
    	rep(i,1,n) forn(j,1,m + 1) {
    		if(b[i][j] < b[i + 1][j]) Add(j, m + i + 1), d[m + i + 1] ++ ;
    		else if(b[i][j] > b[i + 1][j]) Add(m + i + 1, j), d[j] ++ ;
    	}
    	static int que[N * N << 1], he, tl;
    	he = 1, tl = 0;
    	forn(i,1,m + 1) if(!d[i]) que[++tl] = i, vis[i] = 1;
    	res.reserve(n);
    	while(he <= tl && !vis[m + 1]) {
    		int u = que[he++];
    		if(u <= m + 1) {
    			res.push_back(u);
    			IT(u) if(!vis[E[i].dir]) que[++tl] = E[i].dir, vis[E[i].dir] = 1;
    		} else IT(u) if(!--d[E[i].dir]) que[++tl] = E[i].dir, vis[E[i].dir] = 1;
    	}
    	if(!vis[m + 1]) return puts("-1"), 0;
    	printf("%d
    ", (int)res.size());
    	form(i,res.size() - 1,0) printf("%d%c", res[i], " 
    "[i == 0]);
    	return 0;
    }
    
    
  • 相关阅读:
    nodejs内存溢出解决方法
    mongodb副本集与分片结合
    node加密
    守护进程,互斥锁,IPC,队列,生产者与消费者模型
    并发编程
    粘包问题
    socket编程
    xml模块
    网络编程
    异常处理
  • 原文地址:https://www.cnblogs.com/Ax-Dea/p/15233853.html
Copyright © 2020-2023  润新知