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<bits/stdc++.h>
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');
}
}