题意:求给定字符串(有重复字符)第k大排列。
解法:先判断字符串的所有排列是否够k个。然后从左向右每一位每一位确定。简单的组合数学。
代码:
/**************************************************** * author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> using namespace std; #define eps 1e-8 typedef long long LL; char s[30]; int per; int len=0; LL fac[21]; struct point { char c; int x; } points[100]; int tot=0; void init() { fac[0]=1; for(LL i=1; i<=20; i++) fac[i]=fac[i-1]*i; } LL cal() { LL tool=1; int t=0; for(int i=0; i<=tot; i++) t+=points[i].x,tool*=fac[points[i].x]; return fac[t]/tool; } void solve() { if(cal()<per) { printf("Impossible\n"); return ; } for(int i=0; i<len; i++) { LL tool=0; int j; for(j=0;j<=tot;j++) { points[j].x--; LL now=cal(); tool+=now; if(tool>=per) { putchar(points[j].c); per-=tool-now; break; } points[j].x++; } if(points[j].x==0) { for(int k=j; k<tot; k++) points[k]=points[k+1]; tot--; } } puts(""); } int main() { int t; cin>>t; int kk=1; init(); while(t--) { tot=0; scanf("%s%d",s,&per); len=strlen(s); sort(s,s+len); points[tot].c=s[0]; points[tot].x=1; for(int i=1; i<len; i++) { if(s[i]==s[i-1]) points[tot].x++; else { points[++tot].c=s[i]; points[tot].x=1; } } printf("Case %d: ",kk++); solve(); } return 0; }
ligh1060(求字符串第k大排列)组合数学
时间: 2024-10-21 11:30:45