而且题目给的 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;
}
原文地址:http://blog.csdn.net/u014664226/article/details/45875991