分析
首先一列的数不会发生变化,只是交换列,
并且交换列的时候奇数列变成偶数列取反,
偶数列变成奇数列取反,考虑直接将偶数列全部取反,
那只需要交换列就可以了,奇数列交换到偶数列会取反,
奇数列交换到奇数列不变;偶数列同理
如果将上下两行看成一个整体,通过初始状态给目标状态的每一列重新编号,
那就变成了经典的逆序对问题,
不过首先要判断上下两行是否双射,这可以采用哈希,
当然由于数字比较小,直接用个桶就行了,但我不改了(mapTLE了)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
const int N=1000011,p=1500007;
lll ans,a[3][N],b[3][N]; int n,c[N],A[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline lll query(int x){
rr lll ans=0;
for (;x;x-=-x&x) ans+=c[x];
return ans;
}
inline void update(int x,int y){
for (;x<=n;x+=-x&x) c[x]+=y;
}
struct hash{
struct node{int y; lll w; int next;}e[p]; int hs[p],tot;
inline void add(int x,lll w){e[++tot]=(node){x,w,hs[w%p]},hs[w%p]=tot;}
inline signed locate(lll x){
for (rr int j=hs[x%p];j;j=e[j].next)
if (e[j].w==x) return e[j].y;
return -1;
}
}h;
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[1][i]=iut();
for (rr int i=1;i<=n;++i) a[2][i]=iut();
for (rr int i=1;i<=n;++i) b[1][i]=iut();
for (rr int i=1;i<=n;++i) b[2][i]=iut();
for (rr int i=2;i<=n;i+=2)
swap(a[1][i],a[2][i]),swap(b[1][i],b[2][i]);
for (rr int i=1;i<=n;++i) a[0][i]=a[1][i]<<30|a[2][i];
for (rr int i=1;i<=n;++i) b[0][i]=b[1][i]<<30|b[2][i];
for (rr int i=1;i<=n;++i) h.add(i,a[0][i]);
for (rr int i=1,t;i<=n;++i)
if (~(t=h.locate(b[0][i]))) A[i]=t;
else return !printf("dldsgay!!1");
for (rr int i=n;i;--i)
ans+=query(A[i]-1),update(A[i],1);
return !printf("%lld",ans);
}