Description&Data Constraint
让我们来考虑 1 到 N N N 的正整数集合。让我们把集合中的元素按照字典序排列,例如当 N = 11 N=11 N=11 时,其顺序应该为: 1 , 10 , 11 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 1,10,11,2,3,4,5,6,7,8,9 1,10,11,2,3,4,5,6,7,8,9。
定义 K K K 在 N N N 个数中的位置为 Q ( N , K ) Q(N,K) Q(N,K),例如 Q ( 11 , 2 ) = 4 Q(11,2)=4 Q(11,2)=4。现在给出整数 K K K 和 M M M,要求找到最小的 N N N,使得 Q ( N , K ) = M Q(N,K)=M Q(N,K)=M。
1 ≤ K , M ≤ 1 0 9 1\le K,M\le10^9 1≤K,M≤109
Solution
首先从特殊往一般想。
考虑当 K = 1 0 i K=10^i K=10i 的时候的情况。由于其字典序最小,因此位置是固定的,即 i + 1 i+1 i+1,那么只要 M M M 不是这个位置都是无解。
既然是位置,可以考虑先求出 K K K 的最小位置。
思考在 K K K 前面的会有多少。假设 K = 114514 K=114514 K=114514。
- 114514 − 100000 + 1 = 14515 114514-100000+1=14515 114514−100000+1=14515。这是在位数一样的情况下。
- 11451 − 10000 + 1 = 11452 11451-10000+1=11452 11451−10000+1=11452。这是在少一位的情况下。
- 1145 − 1000 + 1 = 1146 1145-1000+1=1146 1145−1000+1=1146。同上,以此类推。
- 114 − 100 + 1 = 15 114-100+1=15 114−100+1=15。同上,以此类推。
- 11 − 10 + 1 = 2 11-10+1=2 11−10+1=2。同上,以此类推。
- 1 − 1 + 1 = 1 1-1+1=1 1−1+1=1。同上,以此类推。
因此可以发现,在比 K K K 少 i i i 位的情况下,将会有(设 K K K 的长度是 l e n len len) ⌊ K 1 0 i ⌋ − 1 0 l e n − i + 1 \lfloor\dfrac{K}{10^i}\rfloor-10^{len-i}+1 ⌊10iK⌋−10len−i+1 个数的字典序比 K K K 小。
统计出 K K K 的最小位置 n u m num num 后,将 n u m num num 和 M M M 进行比较。
若 n u m = M num=M num=M,那么只要出现了 K K K 就可以使得 K K K 的位置是 M M M,因此 N N N 的最小值就是 K K K。
若 n u m > M num>M num>M,就无解了,因为 n u m num num 是 K K K 的最小位置。不存在其他的位置比 n u m num num 还要小。
若 n u m < M num<M num<M,就说明还有比 K K K 前面的数,但是位数小于等于 K K K 的已经穷举完了,因此肯定有位数大于 K K K 的在 K K K 前面。逐步增加位数,同时更新最小位数。当某个时刻 n u m ≥ M num\ge M num≥M,先将 n u m num num 减回去,算出 M M M 与 n u m num num 之间的差。再加上 1 0 x 10^{x} 10x ,这个 x x x 是当前位数。最后减去1(因为从0开始算),就是 N N N 的大小。
Code
#include<cmath>
#include<cstdio>
using namespace std;
int len;
long long k,m,num,p[20];
int main()
{
scanf("%lld%lld",&k,&m);
p[0]=1;
for (int i=1;i<=18;++i)
p[i]=p[i-1]*10;
for (int i=0;i<=18;++i)
if (k==p[i])
{
if (m==i+1) printf("%lld\n",k);
else printf("0\n");
return 0;
}
len=(int)log10(k);
for (int i=len;i>=0;--i)
num+=k/p[i]-p[len-i]+1;
if (num==m) printf("%lld\n",k);
else if (num>m) printf("0\n");
else
{
for (int i=1;i<=10;++i)
{
k*=10;
num+=k-p[len+i];
if (num>=m)
{
num-=k-p[len+i];
printf("%lld\n",m-num+p[len+i]-1);
return 0;
}
}
}
return 0;
}