P2022

一道非常思路非常清奇的的题。。卡在了一个点上了

我们要注意

假设 在 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值