LightOJ 1060 nth Permutation(组合数--k大字典序)

题目

给一串长度不超过20的字符串,求n-th permutation of the string. 0<n<231

思路

先排序,求出当前串有K种组合,如果n大于k,显然impossible;
然后就是每个位置枚举字符,判断下合理性就行了;

char s[30];
long long f[22];
typedef struct item {
    char c;
    int num;
    item() {c = '\0';num = 0;}
}item;
item p[20];
int tot;

void init() {
    f[0] = 1;
    for (int i = 1;i < 21;++i)
        f[i] = 1ll*f[i-1]*i;
    // Rep(i, 1, 20) cout << f[i] << endl;
}

long long calc() {
    LL t1 = 0, t2 = 1;
    for (int i = 0;i <= tot;++i) {
        t1 += p[i].num;
        t2 *= f[p[i].num];
    }
    // cout << f[t1] << ' ' << t2 << endl;
    return f[t1] / t2;
}

void solve(int k, int len) {
    if (calc() < k) {
        printf("Impossible\n");
        return ;
    }

    for (int i = 1;i <= len;++i) {
        long long t = 0;
        int j;
        for (j = 0;j <= tot;++j) {
            p[j].num--;
            long long now = calc();
            t += now;
            if (t >= k) {
                putchar(p[j].c);
                k -= (t - now);
                break;
            }
            p[j].num++;
        }
        if (p[j].num == 0) {
            for (int o = j;o < tot;++o)
                p[o] = p[o+1];
            --tot;
        }
    }
    puts("");
}
int main(int argc, const char * argv[])
{   int kase;cin >> kase;
    init();
    while(kase--) {
        int k;
        scanf("%s%d", s + 1,&k);
        int len = strlen(s + 1);
        sort(s + 1, s + 1 + len);
        tot = 0;
        p[tot].c = s[1];
        p[tot].num = 1;
        for (int i = 2;i <= len;++i) {
            if (s[i] == s[i - 1]) p[tot].num++;
            else {
                ++tot;
                p[tot].c = s[i];
                p[tot].num = 1;
            }
        }
        printf("Case %d: ", ++nCase);
        solve(k, len);
    }
    // showtime;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值