码迷,mamicode.com
首页 > 其他好文 > 详细

lightoj 1060 - nth Permutation(组合数+贪心)

时间:2017-07-09 13:42:51      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:iostream   for   思想   [1]   problem   操作   ios   一个   递增   

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1060

 

题解:如果是不重复数的这些操作可以用康托展开的逆来求,如果是有重复数字出现康托展开的逆就要稍微变一下。要除去自身个数的组合数具体看一代码,暴力就行

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
ll f[30];
char s[30];
int num[30];
void init() {
    f[1] = f[0] = 1;
    for(int i = 2 ; i <= 20 ; i++) f[i] = f[i - 1] * i;
}
int main() {
    int t , Case = 0;
    scanf("%d" , &t);
    init();
    while(t--) {
        int n;
        scanf("%s %d" , s , &n);
        memset(num , 0 , sizeof(num));
        int len = strlen(s);
        for(int i = 0 ; i < len ; i++) {
            num[s[i] - ‘a‘]++;
        }
        ll Max = f[len];
        for(int i = 0 ; i < 26 ; i++) if(num[i]) Max /= f[num[i]];//最多的组合种类
        printf("Case %d: " , ++Case);
        if(Max < n) { printf("Impossible\n"); continue; }
        for(int i = 0 ; i < len ; i++) {
            for(int j = 0 ; j < 26 ; j++) {
                if(!num[j]) continue;
                ll gg = f[len - i - 1];
                num[j]--;
                for(int l = 0 ; l < 26 ; l++) if(num[l]) gg /= f[num[l]];
                if(gg >= n) {
                    putchar(j + ‘a‘);
                    break;
                }//如果取当第j个字母为当前位的组合数大于n那么肯定符合。有种贪心的思想。
                n -= gg;//否则就是下一个字母这里之所以要减去是因为要求递增下去前面的组合都不行到下一组合肯定要减去上一个组合数。
                num[j]++;
            }
            if(i == len - 1) printf("\n");
        }
    }
    return 0;
}

lightoj 1060 - nth Permutation(组合数+贪心)

标签:iostream   for   思想   [1]   problem   操作   ios   一个   递增   

原文地址:http://www.cnblogs.com/TnT2333333/p/7141179.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!