#树状数组,哈希#洛谷 6687 论如何玩转 Excel 表格

题目


分析

首先一列的数不会发生变化,只是交换列,
并且交换列的时候奇数列变成偶数列取反,
偶数列变成奇数列取反,考虑直接将偶数列全部取反,
那只需要交换列就可以了,奇数列交换到偶数列会取反,
奇数列交换到奇数列不变;偶数列同理
如果将上下两行看成一个整体,通过初始状态给目标状态的每一列重新编号,
那就变成了经典的逆序对问题,
不过首先要判断上下两行是否双射,这可以采用哈希,
当然由于数字比较小,直接用个桶就行了,但我不改了(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);
}
posted @ 2020-10-15 17:48  lemondinosaur  阅读(110)  评论(0编辑  收藏  举报