当前位置: 代码迷 >> 综合 >> 2019ACM/ICPC上海网络赛 F Rhyme scheme
  详细解决方案

2019ACM/ICPC上海网络赛 F Rhyme scheme

热度:48   发布时间:2023-12-22 14:04:29.0

一些废话:

这场wtw过了生成函数E题,所以我们不到俩小时的时候就已经五题了。然后开始搞F,百度了贝尔数,但是我们对解决这题没什么头绪。后来cys说他有一点初步的想法,让我们去看别的题。

因为以前有过三个人在一道题上浪费很多时间的经历,我和wtw最终去搞C了,可惜想到了FFT还是没想到怎么做。

比赛最后一小时我放弃了想C题,回来和cys一起想F,他告诉我前面的取值确定之后,下一位的取值是从A到当前的最大字符+1,我说那这个是不是可以dp预处理?然后他说好像可以。其实当时我也没有想的很清楚,所以还是让cys来写。

最后四十分钟的时候cys开始写这题,半小时后完成,结果最后十分钟我们花在了弄int128的输入上(我忘了我的输入模板没有忽略空格),导致没有时间对代码逻辑进行debug,很遗憾WA了。

F Rhyme scheme

题目大意:

用n位字符串来表示n个物品的集合划分(贝尔数)的所有方案,已知n、k,求满足题意的字典序排行第k的n位字符串。

解法:

由题可知,第i位能填的最大的字符比前i-1位中出现的最大的字符大1。

令dp[maxx][res]表示已出现过的最大字符为maxx,当前还剩下res位没有填的合法方案数,那么可以通过记忆化搜索,预处理出dp数组。

通过预处理出的dp数组,可以确定当前位应该填的字符,直接dfs即可。

#include<bits/stdc++.h>
using namespace std;
void scan(__int128 &x)//输入
{x = 0;int f = 1;char ch;while((ch=getchar())==' ')continue;if(ch == '-') f = -f;else x = x*10 + ch-'0';while((ch = getchar()) >= '0' && ch <='9')x = x*10 + ch-'0';x *= f;
}
int n;
__int128 k,dp[30][30];
__int128 dfs1(int res,int maxx){//预处理 if(dp[maxx][res]!=0) return dp[maxx][res];if(res==0) return dp[maxx][res]=1;for(int i=0;i<=maxx+1&&i<26;i++){dp[maxx][res]+=dfs1(res-1,max(maxx,i));}return dp[maxx][res];
}
char ans[30];
void dfs(int now,int res,int maxx,__int128 k){if(res==0) return;for(int i=0;i<=maxx&&i<26;i++){if(k>dp[maxx][res-1]){k-=dp[maxx][res-1];}else{ans[now]=i+'A';dfs(now+1,res-1,maxx,k);return;}}if(maxx+1<26){ans[now]=maxx+1+'A';dfs(now+1,res-1,maxx+1,k);}
}
int t;
int main()
{dfs1(25,0);scanf("%d",&t);for(int cas=1;cas<=t;cas++){memset(ans,0,sizeof(ans));scanf("%d",&n);scan(k);ans[0]='A';dfs(1,n-1,0,k);cout<<"Case #"<<cas<<": "<<ans<<"\n";}return 0;
}

 

  相关解决方案