掘金团队号上线,助你 Offer 临门! 点击 查看详情
一、题目描述:
二、思路分析:
这题最简单思路是递归加遍历,因为字典序所以可以考虑扔优先队列时
但是这样会超时
我们发现,可以将list转换为树的结构,
进行大幅度剪枝,需要考虑的是如何确定是否在当前节点的子树中,如果在,就往下遍历一个节点(指能遍历a就遍历a,否则则是b)。如果不再则说明在其兄弟节点,那么则需要代表a的节点数量++(回到父节点),代表b的数量--(进入兄弟节点)。
三、AC 代码:
#include <iostream>
#include <string>
#include <map>
using namespace std;
map<pair<int,int>,unsigned long long> ma;
unsigned long long f(int m,int n)
{
if(ma.count({m,n}))return ma[{m,n}];
if(!m)ma[{m,n}]=n;
else if(!n)ma[{m,n}]=m;
else ma[{m,n}]=f(m-1,n)+f(m,n-1)+2;
return ma[{m,n}];
}
int main()
{
long long k;
int n,m;
cin>>n>>m>>k;
string cur="a";
n--;
k--;
while(k>0&&(m||n))
{
unsigned long long step=f(n,m)+1;//子树的个数
if(step>k)//k在子树中
{
k--;
if(n)
{
cur+="a";
n--;
}else{
cur+="b";
m--;
}
}else{//k不在子树中,在下一个子树里
k-=step;
n++;
m--;
cur.back() = 'b';
}
}
cout<<cur<<endl;
return 0;
}
四、总结:
在实际实现中并不一定要通过树来存储,可以通过map也好,二维数组也好。
一般就算想到字典树第一反应也是构建这个字典树,而不是假想出字典树并在其上进行操作,本题天马行空很有东西。