UVA 11525 Permutation(线段树第K大数字问题)

题意:

题意:给定一个k个数字,求由 [1,k] 的数字组成的,第n个全排列,由于n很大,输入的方式为 ki=1Si(Ki)!

解析:

一开始把题目理解错了,我还以为是给你 {S1...Sn} ,叫你算出符合 {S1...Sn} 的全排列的第n个,且满足 n=ki=1Si(Ki)!
原来正确的题意:是给你 Sn 叫你先算出 n ,再算出符合条件的由[1,k]的数字组成的,第n个全排列。
那么先算出n再求出全排列那是不可能的,因为n实在是太大了。
其实题目所给出的这个公式其实就是康拓展开的公式,不懂的可以百度百科一下。
由观察得知 (ki)! 就是 ki 个数字的全排列种数, 0=<Si<=ki ,所以显然可知假设当 i=1 时,从第 (k1)!S1 到第n个全排列都是由第 S1+1 个数字开始的数列,因为每 (k1)! 次排列过后,下一个排列的第1个数字都要增大1。

举个例子:
比如我1 2 3 4 5 的全排列
如果以1打头的种数有 4! 种,那我现在要第k大的,假设 k=3 ,那么现在全排列至少是第 (24!+1) 大的,因为1打头有 4! 个, 2打头的有 4! 个,然后你就这样一位一位去确定 现在要的是第多少大的, 并且这个数字是多少。

那么现在问题可以转化为:起初K个人排队,1,2,3,…,K,每次给定一个S,找到当前排第S位的人,让其出列,再如此循环,要求每次都准确找到排第S位的人是哪一个人。注意每一次S都可能不一样,出列后的人不再属于当前队伍。怎么做?用线段树动态查找就可以实现。

my code

#include <cstdio>
#include <cstring>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls,L,M
#define rson rs,M+1,R
using namespace std;
const int N = 50005;

int sumv[N<<2];

void pushUp(int o) {
    sumv[o] = sumv[ls] + sumv[rs];
}

void build(int o, int L, int R) {
    sumv[o] = 0;
    if(L == R) {
        sumv[o] = 1;
        return ;
    }
    int M = (L+R)/2;
    build(lson);
    build(rson);
    pushUp(o);
}

int val;
void modify(int o, int L, int R) {
    if(L == R) {
        sumv[o]--;
        printf("%d", L);
        return ;
    }
    int M = (L+R)/2;
    if(sumv[ls] >= val) {
        modify(lson);
    }else {
        val -= sumv[ls];
        modify(rson);
    }
    pushUp(o);
}

int n;
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        build(1, 1, n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &val);
            val++;
            modify(1, 1, n);
            if(i < n) putchar(' '); 
        }puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值