码迷,mamicode.com
首页 > 编程语言 > 详细

uva 11525排列(树状数组 + 二分)

时间:2015-05-20 22:20:14      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:排列   树状数组   


现在给定k和n,要你按字典序输出 第n种排列的数列

而且题目给的 n是 n=S1(k-1)!+S2(k-2)!+...+Sk-1*1!+Sk*0!(0=<Si<=k-i),

我们可以知道si表示i后面有多少个比a[i]小的数,这样一来首先想到的就是set,但是set不能顺序访问,所以可以用树状数组,初始时置1,消除后置0,然后二分来求和为si + 1的位置

代码如下:

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<cstdlib>  
#include<iostream>  
#include<algorithm>  
#include<vector>  
#include<map>  
#include<queue>  
#include<stack> 
#include<string>
#include<map> 
#include<set>
using namespace std;  
#define LL long long  
const int maxn = 50005;
const int INF = 1000000000;
//freopen("input.txt", "r", stdin);

int c[2 * maxn], s[maxn], ans[maxn], k;

int lowbit(int x) {
	return x&(-x);
}

int sum(int x) {
	int ret = 0;
	while(x > 0) {
		ret += c[x];
		x -= lowbit(x);
	}
	return ret;
}

void add(int x) {
	while(x <= k) {
		c[x] += 1; x += lowbit(x);
	}
}

void subtract(int x) {
	while(x <= k) {
		c[x] -= 1; x += lowbit(x);
	}
}

int main() {
	int t; scanf("%d", &t);
	while(t--) {
		memset(c, 0, sizeof(c));
		cin >> k;
		for(int i = 1; i <= k; i++) add(i);
		
		for(int i = 1; i <= k; i++) {
			int tmp; cin >> tmp;
			int le = 1, ri = k;
			while(le < ri) {
				int mi = (le + ri) >> 1;
				int tsum = sum(mi);
				if(sum(mi) >= tmp + 1) ri = mi;
				else le = mi + 1;
			}
			ans[i] = ri;
			subtract(ans[i]);
		}
		printf("%d", ans[1]);
		for(int i = 2; i <= k; i++) printf(" %d", ans[i]);
		printf("\n");
	}
	return 0;
}











uva 11525排列(树状数组 + 二分)

标签:排列   树状数组   

原文地址:http://blog.csdn.net/u014664226/article/details/45875991

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!