Little Sub and Mr.Potato's Math Problem (构造法)
Little Sub loves math very much. He enjoys counting numbers.
One day, Mr.Potato gives him an interesting math problem. Please help Little Sub solve this problem.
Let's sort the integers according to alphabetical order. For example, when , the order should be: .
We define as the position of number in the sorted numbers. For example, .
Given and , please find the smallest such that .
Input
There are multiple test cases. The first line of the input contains an integer (), indicating the number of test cases. For each test case:
The first and only line contains two integers and (, ).
Output
For each test case, please output the answer in one line. If there is no such , please output "0" (without quotes).
Sample Input
2 2 4 10000001 100000000
Sample Output
11 1000000088888880
题意:如上题
思路:
第一步:我们可以先计算出当前的数前面按照字典序的话,前面有多少数(包括自己)。
(具体计算过程,456.首先是三位数的数在456前面的个数,就是(100->456),然后再就是两位数(10-45),然后再就是一位数1-4,严格遵守字典序)。
第二步:如果说当前的数前面的数的个数大于m的话,这个时候肯定是不符合情况的,如果说刚好凑起来的话,这个时候输出k就可以了。
第三步:经过了第二步,发现当前的数N取k的时候凑不起来,我们就需要通过增加n来使得k的位数往后移动。举个例子,456不够,我们就可以通过添加1000-4560之间的数来使得456的位数往后移动,如果还不够我们就添加10000-45600之间的数使得456的位数往后移动。
第四步:我们需要判断一种特殊情况,比如说 10 10这个样例,10前面的数只有1,但是你如果加100之后的,也不会使得10的位数往后移动,这个时候就应该输出0。(就是这些数的字典序是相对固定的)
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; int T; int k,m; ll base=1; ll get_num(ll x) { ll ans=0; ll tmp=x; while(x){ base*=10; x/=10; } base/=10; ll base1=base; while(tmp) { ans+=(tmp-base1)+1; tmp/=10; base1/=10; } return ans; } int main() { scanf("%d",&T); while(T--) { scanf("%d %d",&k,&m); base=1; ll tmp=get_num(k); m-=tmp; if(m<0) printf("0\n"); else if(m==0) printf("%d\n",k); else if(base==k) printf("0\n"); else{ ll ans=k-base; base*=10; ans*=10; while(m>ans) { m-=ans; ans*=10; base*=10; } printf("%lld\n",base+m-1); } } return 0; }
参考博客:https://www.cnblogs.com/letlifestop/p/10294237.html