UVA 11027 Palindromic Permutation(组合数学)

来源:互联网 发布:触摸屏是怎样编程 编辑:程序博客网 时间:2024/06/06 13:14

题意:
给出字符串,以及n,然后字符串中的字母排序可以组成若干的字符串,有些为回文串,输出第n个回文串,若不存在第n个回文串,输出“XXX”。

解析:
因为n非常大,所以用枚举是由点不太现实的,对于一个字符串,若能重排成回文串,说明每个字母出现的次数都为偶数,或者说为奇数的只有一个(可以放在中间);
然后这样我们就可以将字符缩减一半,构造左半边的字符串(注意若有单个字符输出时要加上)。
然后根据左边的回文串,构造出目标回文串。

至于怎么求出第K大的全排列字符串,我觉得这篇博文讲的很详细。
http://www.cnblogs.com/scau20110726/archive/2013/02/04/2891543.html

AC代码

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int N = 50;char str[N], ans[N], mid;ll factor[N], cnt[30];int n;int tot, ok;void get_factor() { //计算阶乘    factor[0] = 1;    for(int i = 1; i < 16; i++) {        factor[i] = factor[i-1] * i;    }}ll fun(int sum) { //传入该可重集的个数,返回该可重集的全排列的个数    ll ret = 1;    for(int i = 0; i < 26; i++) {        ret *= factor[cnt[i]];    }    return factor[sum] / ret;}void init() {    memset(ans, 0, sizeof(ans));    memset(cnt, 0, sizeof(cnt));    mid = 0;}void output(int len) {    for(int i = 0; i < len; i++)        putchar(ans[i]);    if(mid) putchar(mid);    for(int i = len - 1; i >= 0; i--)        putchar(ans[i]);    putchar('\n');}bool dfs(int cur) {    if(cur == tot) {        return true;    }    for(int i = 0; i < 26; i++) {        if(cnt[i]) {            cnt[i]--;            ll ret = fun(tot - cur - 1);            cnt[i]++;            if(ret < n) {                n -= ret;            }else {                ans[cur++] = 'a' + i;                cnt[i]--;                if(dfs(cur)) {                    return true;                }            }        }    }    return false;}int main() {    get_factor();    int T, cas = 1;    scanf("%d", &T);    while(T--) {        init();        scanf("%s%d",str, &n);        for(int i = 0; str[i]; i++) { //统计每个字符出现的次数            cnt[str[i] - 'a']++;        }        int flag = 0, sum = 0;        for(int i = 0; i < 26; i++) {            if(cnt[i] & 1) {                flag++;                mid = 'a' + i;            }            cnt[i] >>= 1;            sum += cnt[i];        }        printf("Case %d: ", cas++);        if(flag > 1 || fun(sum) < n) {            printf("XXX\n");        }else {            tot = sum, ok = false;            if(dfs(0))                output(sum);        }    }    return 0;}
0 0