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

来源:互联网 发布:淘宝店铺装修的流程 编辑:程序博客网 时间:2024/05/19 05:33

现在给定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;}

0 0
原创粉丝点击