每周一dp,准备没事做个dp题,因为自己dp太弱了
题目地址,PS.lightoj有个地方挺好的,有题目分类
Given a string of characters, we can permute the individual characters to make new strings. At first we order the string into alphabetical order. Then we start permuting it.
For example the string 'abba' gives rise to the following 6 distinct permutations in alphabetical order.
aabb 1
abab 2
abba 3
baab 4
baba 5
bbaa 6
Given a string, you have to find the **nth
** permutation for that string. For the above case 'aabb' is the 1st
and 'baab' is the 4th
permutation.
题目就是说给你一个字符串,和一个n,问这个字符串的排列的第n个是啥,
比如
abc 1
acb 2
bac 3
bca 4
cab 5
cba 6
bca就是第四个排列。
很明显的,这是个逆康拓展开,然后有重复元素。
我们直接算就行了,其实这个题感觉也算不上是dp,不过lightoj把他放在了dp这个分类。
#include <cstdio>
#include <cstring>
long long f[21];
int cnt[26];
char str[21];
int n;
int main() {
f[0] = 1;
for (int i = 1; i <= 20; i++) {
f[i] = f[i - 1] * i;
}
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
scanf("%s%d", str, &n);
memset(cnt, 0, sizeof(cnt));
int len = strlen(str);
for (int i = 0; i < len; i++) {
cnt[str[i] - 'a'] ++;
}
long long tot = f[len];
for (int i = 0; i < 26; i++) {
// printf("%d %d %lld\n", i, cnt[i], f[cnt[i]]);
tot /= f[cnt[i]];
}
printf("Case %d: ", cas);
if (tot < n) {
printf("Impossible\n");
continue;
}
for (int i = 0; i < len; i++) {
for (int j = 0; j < 26; j++) {
if (cnt[j] > 0) {
cnt[j]--;
tot = f[len - i - 1];
for (int k = 0; k < 26; k++) {
// printf("%d %d %lld\n", k, cnt[k], f[cnt[k]]);
tot /= f[cnt[k]];
}
if (tot >= n) {
printf("%c", j + 'a');
break;
}
n -= tot;
cnt[j]++;
}
}
}
printf("\n");
}
return 0;
}