P6687

对于数组\(a[i]\),在其值域建立一个树状数组,每有一个\(a[i]\)\(tre[a[i]]\)\(++\)

倒叙扫描每个\(a[i]\),把其加入树状数组

数据大的话离散化

for(int i = 1;i <= n;++i){
    ans += ask(a[i]-1);
    add(a[i],1);
}

旋转\(180\)\(2*2\)矩阵

1 2       4 3
3 4  -->  2 1

列的对应是不变的,match一下

黑白染色

img

黑色格子可以相互到达,白色格子可以相互到达于是我们可以在操作前先判断一下开始到结束的同伴有没有变,黑色格子里的数是否还在黑格子里,白色格子的数是否还在白格子里,然后我们就将问题转换为了交换相邻两列格子,问最少多少步到目标状态,再判一下染色对不对

把每一列格子抽象成一个编号,目标状态抽象成给你\(1\sim n\)的升序序列,最初始状态抽象成每列给子在目标状态下对应的编号,整道题相当于给你一个\(1\sim n\)的无序序列,求逆序对数

树状数组解决

#include<cstdio>
#define N 1000005
using namespace std;
int n,a[3][N],b[3][N],match[N<<1],col[N<<1],c[N],tr[N],num[N];
long long ans;
inline void add(int x,int z) {for(;x <= n;x += x&-x) tr[x] += z;}
inline int sum(int x) {int res = 0;for(;x;x -= x&-x) res += tr[x];return res;}
int main(){
	scanf("%d",&n);
	for(int i = 1;i <= 2;++i)
		for(int j = 1;j <= n;++j)
			scanf("%d",&a[i][j]);
	for(int i = 1;i <= 2;++i)
		for(int j = 1;j <= n;++j)
			scanf("%d",&b[i][j]);
	for(int i = 1;i <= n;++i) 
		match[a[1][i]] = a[2][i],match[a[2][i]] = a[1][i];
	for(int i = 1;i <= n;++i)
		if(match[b[1][i]] != b[2][i]){
			puts("dldsgay!!1"); return 0;
		}
	for(int i = 1;i <= 2;++i)
		for(int j = 1;j <= n;++j)
			col[a[i][j]] = (i + j) & 1;
	for(int i = 1;i <= 2;++i)
		for(int j = 1;j <= n;++j)
			if(col[b[i][j]] != ((i + j) & 1)){
				puts("dldsgay!!1"); return 0;
			}
	for(int i = 1;i <= n;++i)
		c[b[1][i]] = i,c[b[2][i]] = i;
	for(int i = 1;i <= n;++i) num[i] = c[a[1][i]];
	for(int i = 1;i <= n;++i){
		ans += sum(n) - sum(num[i]);
		add(num[i],1);
	}
	printf("%lld\n",ans);
}
posted @ 2020-09-20 14:52  INFP  阅读(103)  评论(0编辑  收藏  举报