数列还原 2017网易校招(树状数组预处理+全排列)

本文探讨了一个关于数列的问题,即如何确定一个特定的数列排列,该排列需包含从1到n的数字,并满足一定的顺序对数量。文章提供了一种通过全排列枚举的方法来解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制:1秒  空间限制:32768K  热度指数:5122
 算法知识视频讲解

题目描述

牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10 个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。

输入描述:

每个输入包含一个测试用例。每个测试用例的第一行包含两个整数 n 和 k(1 <= n <= 100, 0 <= k <= 1000000000),接下来的 1 行,包含 n 个数字表示排列 A,其中等于0的项表示看不清的位置(不超过 10 个)。

输出描述:

输出一行表示合法的排列数目。
示例1

输入

5 5
4 0 0 2 0

输出

2
#include <bits/stdc++.h>
using namespace std;
set<int>st;
int a[111], c[111], cnt[111], b[11][111], tot, num[11], n, k, have, cc[111];
inline int lowbit(int x){
	return x & (-x);
}
void add(int c[], int x, int v){
	while(x <= n){
		c[x] += v;
		x += lowbit(x);
	}
}
int query(int c[], int x){
	int ans = 0;
	while(x){
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}
bool check(){
	int all = have;
	for(int i = 1; i <= tot; ++i){
		all += b[i][num[i]];
	}
	memset(cc, 0, sizeof(cc));
	for(int i = 1; i <= tot; ++i){
		all += query(cc, num[i]);
		add(cc, num[i], 1);
	}
	if(all == k){
		return true;
	}
	else{
		return false;
	}
}
int main(){
	cin >> n >> k;
	memset(c, 0, sizeof(c));
	have = 0;
	tot = 0;
	for(int i = 1; i <= n; ++i){
		scanf("%d", &a[i]);
		if(a[i] == 0){
			tot++;
			for(int j = 1; j <= n; ++j){
				b[tot][j] = query(c, j);
			}
			continue;
		}
		cnt[a[i]] = 1;
		have += query(c, a[i]);
		add(c, a[i], 1);
	}
	memset(c, 0, sizeof(c));
	int x = 0;
	for(int i = n; i >= 1; --i){
		if(a[i] != 0){
			add(c, a[i], 1);
		}
		else{
			for(int j = 1; j <= n; ++j){
				b[tot][j] += n - i - x - query(c, j);
			}
			x++;
			tot--;
		}
	}
	for(int i = 1; i <= n; ++i){
		if(cnt[i] == 0){
			st.insert(i);
		}
	}
	tot = 0;
	int ans = 0;
	set<int>::iterator it;
	for(it = st.begin(); it != st.end(); ++it){
		num[++tot] = *it;
	}
	sort(num + 1, num + 1 + tot);
	do{
		if(check()){
			ans++;
		}
	}while(next_permutation(num + 1, num + 1 + tot));
	cout << ans << endl;
}

/*
题意:
一个1到n的排列,有不超过10个数看不清了,现在让你还原这个数列,使得正序列对数为k。

思路:
这题的数据是真的弱。。我是n!log(10), 4ms过的。
先n^2log(n)预处理一下每个为0的位置填1到n的时候分别会对清楚的位置增加多少个正序列对,
然后nlog(n)求一下清楚的部分的正序列对数。
然后全排列枚举,这样对于新填的数对于清楚的数的影响可以O(1)求,然后对于新填的数的序列
求一下正序列数,加一下判断一下即可。
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值