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

LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

时间:2016-01-16 19:07:23      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:

一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427

一开始我还用搜索。。后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!*...*Nn!),

然后就靠自己YY出解法,搞了好几天,最后向学长要了数据,然后迷迷糊糊调了,终于AC了。

后来才知道当时想的解法类似于逆康托展开,只是逆康托展开是对于没有重复元素全排列而言,不过有没有重复元素都一个样。

而现在做这题很顺,因为思路很清晰了,另外这做法和数论DP的统计部分有相似之处。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 long long fact[21]={1};
 5 long long calu(int n,int *cnt){
 6     long long res=fact[n];
 7     for(int i=0; i<26; ++i) res/=fact[cnt[i]];
 8     return res;
 9 }
10 int main(){
11     for(int i=1; i<21; ++i) fact[i]=fact[i-1]*i;
12     char str[22];
13     long long n;
14     int t;
15     scanf("%d",&t);
16     for(int cse=1; cse<=t; ++cse){
17         scanf("%s%lld",str,&n);
18         int sn=strlen(str),cnt[26]={0};
19         for(int i=0; i<sn; ++i) ++cnt[str[i]-a];
20         if(calu(sn,cnt)<n){
21             printf("Case %d: Impossible\n",cse);
22             continue;
23         }
24         printf("Case %d: ",cse);
25         for(int i=0; i<sn; ++i){
26             for(int j=0; j<26; ++j){
27                 if(cnt[j]==0) continue;
28                 --cnt[j];
29                 if(n>calu(sn-i-1,cnt)){
30                     n-=calu(sn-i-1,cnt);
31                     ++cnt[j];
32                 }else{
33                     putchar(j+a);
34                     break;
35                 }
36             }
37         }
38         putchar(\n);
39     }
40     return 0;
41 }

 

LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

标签:

原文地址:http://www.cnblogs.com/WABoss/p/5135911.html

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