https://nanti.jisuanke.com/t/41414
题意:你需要构造一个长度为n的序列,并且每个字符的大小最多是前面出现的最大的字符+1,问你字典序第k大的是多少。
思路:设 f ( n , i , j ) : 【 长 度 为 n 的 字 符 串 , 已 经 写 好 前 i 个 字 符 , 并 且 前 i 个 字 符 最 大 的 一 个 是 j 】 的 方 案 数 f(n,i,j):【长度为n的字符串,已经写好前i个字符,并且前i个字符最大的一个是j】的方案数 f(n,i,j):【长度为n的字符串,已经写好前i个字符,并且前i个字符最大的一个是j】的方案数
那么 f ( n , i , j ) = ( j + 1 ) ∗ f ( n , i + 1 , j ) + f ( n , i + 1 , j + 1 ) , 因 为 要 么 第 i + 1 位 填 最 大 的 j + 1 , 要 么 填 0 j 共 j + 1 种 选 择 。 f(n,i,j)=(j+1)*f(n,i+1,j)+f(n,i+1,j+1),因为要么第i+1位填最大的j+1,要么填0~j共j+1种选择。 f(n,i,j)=(j+1)∗f(n,i+1,j)+f(n,i+1,j+1),因为要么第i+1位填最大的j+1,要么填0 j共j+1种选择。
最后统计答案用dfs划分,一位一位地找。
#include
using namespace std;
int T,n;
__int128 k,f[30][30][30];
void Read()
{
k=0;
char c;
while(!isdigit(c=getchar()))continue;
while(isdigit(c))k=k*10+c-'0',c=getchar();
}
void dp()
{
for(int n=1;n<=26;n++)
{
for(int i=n;i>=1;i--)
{
for(int j=0;j<i;j++)
{
if(i==n)f[n][i][j]=1;
else f[n][i][j]=f[n][i+1][j]*(j+1)+f[n][i+1][j+1];
}
}
}
}
void dfs(__int128 k,int i,int Max)
{
if(!k)return;
for(int j=0;j<=Max+1;j++)
{
int maxx=max(Max,j);
if(k<=f[n][i+1][maxx])
{
putchar('A'+j);
return dfs(k,i+1,maxx);
}
else k-=f[n][i+1][maxx];
}
}
int main()
{
//freopen("input.in","r",stdin);
cin>>T;
dp();
for(int kase=1;kase<=T;kase++)
{
printf("Case #%d: A",kase);
cin>>n;
Read();
dfs(k,1,0);
putchar('\n');
}
}