使用字典树,依次统计以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; }