洛谷 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;
}