使用字典树,依次统计以pre为前缀是否能够满足m个数的需求(pre首先取1),如果能够满足个数需求,说明前缀应该是pre,把pre固定下来,在pre的后面加最小的一个0再继续统计。如果不能够满足个数需求,说明以pre为前缀的数还不够,还需要以pre+1为前缀的数,依次统计直到刚好满足个数需求。
#include <iostream>
using namespace std;
//获取以pre为前缀,不大于n的数的个数,前缀pre也算是一个数;
long get_cnt_of_pre(long pre, long n)
{
long count = 1;
long p = 10;
do
{
long left = pre*p; //以pre为前缀,最左边的子节点的数;
long right = pre*p+p-1; //以pre为前缀,最右边的子节点的数;
if(left > n)
{
//若最左边的子节点都比n大,说明应该结束;
break;
}
if(n >= right)
{
//n比最右边的数大,说明还没有找到最后一行,将当前行所有数都统计进去;
//当前行有p个数;
count += p;
}else {
//n没有比最右边的数大,说明已经找到了最后的一行;
//最后一行只能统计left到n的个数;
count += (n - left) + 1;
break;
}
//定位到下一行;
p*=10;
}while(true);
return count;
}
long solve(long n, long m)
{
long pre = 1;
while(true)
{
long cnt = get_cnt_of_pre(pre,n);
if(cnt >= m)
{
//以pre为前缀能够满足m个数的需求;
//前缀也算是一个数,m减少1;
m--;
if(m==0)
{
//统计的个数刚好为m时结束统计;
break;
}
//在pre后面添加一个0继续探索;
pre *= 10;
}else {
//以pre为前缀不能够满足m个数的需求;
//m减少以pre为前缀的个数;
m-=cnt;
//以pre+1为前缀继续探索;
pre++;
}
}
return pre;
}
int main()
{
long n,m;
cin >> n >> m;
cout << solve(n,m);
return 0;
}
京公网安备 11010502036488号