UVa 11525 Permutation(二分+树状数组)
2015-03-21 12:13
267 查看
题中的展开实际就是康托展开。
可以这样理解:
假设确定了排列的第一位,那么还剩下K-1个数,全排列数为(K-1)!因此答案第一个数一定是S1+1
以此类推,可以得知第i位的答案就是在未选的数中第Si小的。
问题就转化成了如何确定未选的数中第k小的数是多少。
用树状数组c,维护数i之前有多少个数被取走了。这属于单点修改,区间查询。
这样如果i-c[i]>=k,那么i这个位置就是可选的。
用二分法去找满足条件的最小的i。
代码:
可以这样理解:
假设确定了排列的第一位,那么还剩下K-1个数,全排列数为(K-1)!因此答案第一个数一定是S1+1
以此类推,可以得知第i位的答案就是在未选的数中第Si小的。
问题就转化成了如何确定未选的数中第k小的数是多少。
用树状数组c,维护数i之前有多少个数被取走了。这属于单点修改,区间查询。
这样如果i-c[i]>=k,那么i这个位置就是可选的。
用二分法去找满足条件的最小的i。
代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #include <algorithm> #define maxn 50005 int c[maxn]; int K; int lowbit(int n){ return n&(-n); } void add(int pos){ while(pos<=K){ c[pos]++; pos+=lowbit(pos); } } int query(int pos){ int res=0; while(pos>0){ res+=c[pos]; pos-=lowbit(pos); } return res; } int BS(int num){ int l=0,r=K+1; while(l<r-1){ int mid=(l+r)/2; if(mid-query(mid)>=num) r=mid; else l=mid; } return r; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&K); memset(c,0,sizeof(c)); for(int i=0;i<K;i++){ int t; scanf("%d",&t); t++; int k=BS(t); printf("%d",k); if(i==K-1) printf("\n"); else printf(" "); add(k); } } return 0; } /* 5 3 0 0 0 3 2 1 0 3 1 0 0 4 2 1 1 0 4 1 2 1 0 */
相关文章推荐
- UVa11525 康托展开+二分+树状数组
- 11525 - Permutation(二分+树状数组)
- 全排列 UVA 11525 Permutation
- UVA 11525 Permutation
- uva 11525排列(树状数组 + 二分)
- UVA 11525 Permutation(线段树第K大数字问题)
- UVA - 11525 Permutation
- UVA 11525 - Permutation(树状数组)
- Uva 11525 Permutation
- UVA_11525 树状数组的活用 二分
- Uva-11525-Permutation
- UVA 11525 Permutation(树状数组)
- uva 11525 Permutation
- uva 11525 - Permutation(线段树)
- uva 11525 Permutation
- UVa 11525 - Permutation (线段树 树状数组 康托展开式)
- 【UVA】11525-Permutation(线段树水题)
- UVA 11525 Permutation(树状数组)
- UVaLive 11525 Permutation (线段树)
- UVa 11525 Permutation (线段树)