一道谷外题,做法不知道为啥假了
  • 板块学术版
  • 楼主chlchl
  • 当前回复10
  • 已保存回复10
  • 发布时间2022/9/4 12:44
  • 上次更新2023/10/27 12:36:07
查看原帖
一道谷外题,做法不知道为啥假了
363036
chlchl楼主2022/9/4 12:44

题目描述 给出一个 1n1\sim n 的排列 pp,并给出下述两种操作:

  1. p1p_1p2p_2p3p_3p4p_4、…、p2n1p_{2n-1}p2np_{2n} 交换;
  2. p1p_1pn+1p_{n+1}、…、pnp_np2np_{2n} 交换。 请问最少多少步操作能够使得排列成为从小到大排序的呢?

显然同一种操作不能连续两次,所以直接交替操作。但是我一开始没想到,用了逆序对个数判断到底进行哪个操作,结果只有 9090

但是后来我又想到了交替的方法,但是还是使用了逆序对判断,还是 9090 分。所以我想问一下到底假在哪了(WA 的那个点偷不到数据)。

附上代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 2000 + 10;
int n, op, dis, ans = 1, a[N], b[N], c[N];
int sum[N];

void update(int i, int x){for(;i<=n*2;i+=i&-i)	sum[i] += x;}

int query(int i){
	int res = 0;
	for(;i;i-=i&-i)	res += sum[i];
	return res;
}

int getnxd(int *d){
	int tot = 0;
	memset(sum, 0, sizeof(sum));
	for(int i=1;i<=n*2;i++){
		tot += i - 1 - query(d[i]);
		update(d[i], 1);
	}
	return tot;
}

int main(){
	scanf("%d", &n);
	for(int i=1;i<=n*2;i++)	scanf("%d", &a[i]);
	dis = getnxd(a);
	if(!dis)	return printf("0\n"), 0;
	
	for(int i=1;i<=n*2;i++)	b[i] = c[i] = a[i];
	for(int i=1;i<=n;i++)	swap(b[i * 2 - 1], b[i * 2]), swap(c[i], c[n + i]);
	int cnt1 = getnxd(b), cnt2 = getnxd(c);
	if(cnt1 >= cnt2 && cnt2 < dis)	for(int i=1;i<=n*2;i++)	a[i] = c[i], op = 0;
	else if(cnt1 < cnt2 && cnt1 < dis)	for(int i=1;i<=n*2;i++)	a[i] = b[i], op = 1;
	dis = min(cnt1, cnt2);
	if(!dis)	return printf("1\n"), 0;
	
	while(dis > 0){//连续进行两种操作并没有意义 
		op ^= 1;
		for(int i=1;i<=n*2;i++)	b[i] = a[i];
		if(op)	for(int i=1;i<=n;i++)	swap(b[i * 2 - 1], b[i * 2]);
		else	for(int i=1;i<=n;i++)	swap(b[i], b[n + i]);
		int cnt = getnxd(b);
		if(cnt >= dis)	return printf("-1\n"), 0;
		dis = cnt, ++ans;
		for(int i=1;i<=n*2;i++)	a[i] = b[i];
	}
	printf("%d\n", ans);
	return 0;
}
2022/9/4 12:44
加载中...