一道非常思路非常清奇的的题。。卡在了一个点上了
我们要注意
假设 在 11前边再加个数字
比如 1-102 的排列 我们据前几个的例子排列为
1 ,10 ,100 ,101, 102 ,11, 2 。。。。。
所以要注意字典序排列是这样的
我们先去想几个思路 假设 对于 k 来讲 k 是最大序列的时候
我们找比 K 小的数字 我们发现 假设 K = 23
那么 1, 10-19, 2, 20, 21, 22, 23
其中 23-10之间的数字 还有 2-1之间的数字都在 23之前,我们就可以大胆猜测
计算 23 数字之前的数字个数方法: 23-10 + 2-1
而 233 数字之前数字个数 就是 : 233-100 + 23-10 + 2-1
那么 如果 m < 这个数 base 的话 显然 没有可行解,直接输出 0 吧,=base 直接输出 k
之后 对于 m > base 的时候
我们就得在 10后边加一位 扩大一位。。。(这里百度了一下字典序恍然大悟,发现这个字典序排列不是我想象中那样)
当然 对于一个数字 举例 233
如果 m > base 我们就需要在前边加数字
每次加的数字是确定的
每次加 1000-1999 还有 2000-2329 (可以自行字典序脑补一下)
那么多加了几个数字 我们发现了一个规律
多加的数字 = k*10 - 10^x (x 是 k 的位数)
我们知道 m > base 后 还要添加 base - m 个数字
那么问题来了 会不会无解呢? 当然不会,既然 m > base,
举个例子 以 233 为例 我们是从 1000开始的 那么我们想加到哪就加到哪。。。随时停止 知道位置符合就好了
首先 先假设 添了这 2330 - 1000 个数字 发现 还不够。。我们就只能去从10000开始了
假设 刚好到 10000能搜到结果,那么 我们的结果就是 10000 + m-base 对吧
但是如果 1000 以上的时候就能找得到结果 直接就是 1000+m-base 对吧
当然 最后输出的是 1000 + m - base - 1 (这里别漏了自己)
最终就是结果了,如果增十倍 大了 说明当前这个位数内能搞到 是 10^x + base - m - 1
如果不行就增加 10 倍数,理论上 数据最大 10^9 能搞到。。
但是问题来了 如果询问的是 10 100 1000 这种数字。。这样跑一下会出问题。。。可能会涨的太大(几个点 RE 了)
所以剪枝一下,特判10 100 1000 这些点。。
题中我开到了 10^19 估计够用了。。
以下是 AC 代码。。。(大脑爆炸的题目,貌似和ZOJ 1月月赛一道题一样)
鸣谢题解第一个巨巨对于求 base 函数的思路。。。之前根本忘了 sprintf 这个神仙操作 作者: Akashicw
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
int k,m;
int base,t;
ll _10[20];
ll ans;
int get(int k)//得到 base
{
char s[12];
sprintf(s,"%d",k);
int ans=0,w=0;
t = strlen(s);
for(int i=0;i<t;i++)
{
w = w*10 + s[i]-'0';
ans += w - _10[i]+1;
}
return ans;
}
int main()
{
_10[0] = 1;
for(int i=1;i<19;i++){ _10[i] = _10[i-1]*10;}
scanf("%d%d",&k,&m);
for(int i=0;i<19;i++)if(k==_10[i] && m!=i+1){printf("0\n"); return 0;}
base = get(k);
if(m < base){printf("0\n"); return 0;}
if(m == base){printf("%d\n",k); return 0;}
ans = _10[t];
m -= base;
for(int i=1;;i++)
{
ll tmp=k*_10[i]-_10[t+i-1];
if(m>tmp)
{
m-=tmp;
ans*=10;
}
else
{
break;
}
}
ans += m-1;
printf("%lld\n",ans);
return 0;
}