2019上海icpc网络赛F Rhyme scheme

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):niij
那么 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+1j+10 jj+1
最后统计答案用dfs划分,一位一位地找。
2019上海icpc网络赛F Rhyme scheme_第1张图片

#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');
	}
}

你可能感兴趣的:(线性DP)