洛谷 P2022 有趣的数 题解

一、题目:

洛谷原题

二、思路:

实在想不出来啊!!!又无耻看题解。完了,今年提高组要凉。

数学推导。

首先考虑K所有可能的位置中,最小的那一个。

以K=234为例,计算K之前(包括K)有几个元素:

一位数:1~2(2个)

两位数:10~23(14个)

三位数:100~234(135个)

所以K=234时,最小可能的位置是2+14+135=151。

记K最小可能的位置是pos,那么显然有:

如果pos==m,答案就是K。

如果pos>m,无解。

如果pos<m,我们要在K之前加入m-pos个元素。

挨个位数加呗。

两位数不够加三位数,三位数不够加四位数,四位数不够加五位数……

如果够了,跳出循环即可。

具体实现看代码。

三、代码:

#include<iostream>
#include<cstdio>
#include<cstring>

#define LL long long

using namespace std;
template<class Type>
inline Type read(void){
    Type x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}

int K,m;
int base,len;
LL mi[20];//mi[i]为10的i次幂。
LL ans;

inline int calc(int k){
    char s[12]={0};
    sprintf(s,"%d",k);
    int ans=0,w=0;
    len=strlen(s);
    for(register int i=0;i<len;++i){
        w=w*10+s[i]-'0';
        ans+=w-mi[i]+1;
    }
    return ans;
}

int main(){
    mi[0]=1;
    for(register int i=1;i<19;++i)mi[i]=mi[i-1]*10;
    K=read<int>();
    m=read<int>();
    for(register int i=0;i<10;++i){
        if(K==mi[i]&&m!=i+1){
            cout<<0<<endl;return 0;
        }
    }
    base=calc(K);//计算pos。
    if(m<base){cout<<0<<endl;return 0;}
    if(m==base){cout<<K<<endl;return 0;}
    ans=mi[len];
    m-=base;
    for(register int i=1;;++i){//挨个位数加。
        LL tmp=K*mi[i]-mi[len+i-1];
        if(m>tmp){m-=tmp;ans*=10;}
        else break;
    }
    ans+=m-1;//注意细节。
    cout<<ans<<endl;//李煜东:卡什么常啊,能不能有点追求。我:要有追求!
    return 0;
}
posted @ 2018-10-14 22:25  蓝田日暖玉生烟  阅读(329)  评论(0编辑  收藏  举报