首先发现行之间的先后顺序之和它在最后一次修改中修改成了什么有关。于是倒序考虑。
倒序考虑一列什么时候可以操作。如果有两行 \(i,j\) 的顺序之前没有被确定,在在这次操作被确定,而且不符合最后顺序的要求,那么这一列就是不能在这个时候被操作的。
于是可以对于每一列,记录还有多少对 \((i,j)\),第 \(i\) 行和第 \(j\) 行间关系如上述。只有当这个值为 \(0\) 时这一行才可以操作。这可以类似一个拓扑排序解决。
但是这样要记录所有 \((i,j)\) 行之间的关系,复杂度 \(O(n^3)\)(\(n,m\) 同阶)。我在这里卡住了。事实上只用记录结束状态两行之间的大小关系。这样就是 \(O(n^2)\) 的了。
除此之外,初始状态也可能直接影响操作完之后的状态,所以可以将初始的第 \(i\) 行后面加上一个 \(i\)。结束状态对应加上。实现上,要注意如果像样例 \(3\) 有若干行完全相同,可以都按从大到小的顺序加数。
code:
点击查看代码
int n,m,a[N][N],b[N][N],deg[N],c[N][N],d[N],id[N];
ll pw[N],h[N];bool vis[N];
vector<int> ans;queue<int> q;
mt19937 rnd(time(0));
const ll mod=(ll)1e12+39,base=19260817;
map<ll,vector<int>> mp;
map<ll,int> hs;
il ll Mod(ll x,ll y){return x+y>=mod?x+y-mod:x+y;}
il ll qmul(ll x,ll y){
ll ret=0;
while(y){
if(y&1)ret=Mod(ret,x);
x=Mod(x,x),y>>=1;
}
return ret;
}
il ll qpow(ll x,int y){
ll ret=1;
while(y){
if(y&1)ret=qmul(ret,x);
x=qmul(x,x),y>>=1;
}
return ret;
}
void Yorushika(){
scanf("%d%d",&n,&m);
rep(i,1,n)rep(j,1,m)a[i][j]=read();
rep(i,1,n)rep(j,1,m)b[i][j]=read();
int num=rnd()%(int)1e9+1;
rep(i,1,n)pw[i]=qpow(i,num);
rep(i,1,n){
ll s=0;
rep(j,1,m)s=Mod(qmul(s,base),pw[b[i][j]]);
mp[s].eb(i);
}
drep(i,n,1){
ll s=0;
rep(j,1,m)s=Mod(qmul(s,base),pw[a[i][j]]);
if(!mp[s].size())return puts("-1"),void();
id[mp[s].back()]=i,mp[s].pop_back();
h[i]=Mod(qmul(s,base),pw[i]),a[i][m+1]=i;
}
rep(i,1,n){
b[i][m+1]=id[i];
ll s=0;
rep(j,1,m+1)s=Mod(qmul(s,base),pw[b[i][j]]);
hs[s]=i;
}
rep(j,1,m+1){
rep(i,1,n)d[hs[h[i]]]=a[i][j];
rep(i,1,n-1)if(d[i]<d[i+1])c[j][i]=1;else if(d[i]==d[i+1])c[j][i]=2;else deg[j]++;
if(!deg[j])q.push(j);
}
while(q.size()){
int u=q.front();q.pop();
if(u<=m)ans.eb(u);
rep(i,1,n-1){
if(!vis[i]&&c[u][i]==1){
rep(j,1,m+1)if(!c[j][i]&&!--deg[j])q.push(j);
vis[i]=1;
}
}
if(u==m+1)break;
}
rep(i,1,n-1)if(!vis[i])return puts("-1"),void();
reverse(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int i:ans)printf("%d ",i);
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}