LightOJ 1060 n番目の順列(組み合わせの数-k個の大きな辞書の順序)

トピック

長さが20を超えない文字列の文字列の場合、文字列のn番目の順列を見つけます。 0 < n <231

アイデア

最初に並べ替えて、現在の文字列にKの組み合わせがあることを確認します。nがkより大きい場合、明らかに不可能です。
次に、各位置の文字を列挙し、合理性を判断するだけです。

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;
}

おすすめ

転載: blog.csdn.net/KIJamesQi/article/details/55519353