题目链接:https://ac.nowcoder.com/acm/contest/94570/C
设正整数 ( N ),于 1 至 ( N ) 间,得数若干,数之条件如下:凡数自其末位至首位读之,必奇位(如个位、百位、万位等)皆奇,偶位(如十位、千位、十万位等)皆偶,斯数方称“善数”。若数中位列奇偶而不合此道者,则不谓之善数,弃之无疑。
今有数 ( N ) ,意在求自 1 至 ( N ) 所有“善数”之数,冀能尽得此类,以识奇偶之异妙,亦见“善数”之珍稀也。
解析:
“善数”指奇数位都是奇数,偶数位都是偶数。
因此,我们可以构造出范围内的所有善数
对于一位数,善数有: 1 3 5 7 9
对于两位数,善数有: 21 23 25 27 29 41 43 45 47 49...
我们可以发现, n 位的善数可以看作由 n-1 位的善数在最前面增加一个符合条件的数字。
因此,我们可以得到以下代码:
对于奇数位
int m = 1,temp = 1;
int l = 0,r = 0;
for(int j = 0;j<5;j++)
{
for(int k = l;k<=r;k++)
q[m++] = (j*2+1) * temp;
}
l = r+1,r = m-1;
对于偶数位
for(int j = 1;j<5;j++)
{
for(int k = l;k<=r;k++)
q[m++] = q[k] + (j*2) * temp;
}
l = r+1,r = m-1;
在实际调试中,我们可以发现,对于偶数位为0的情况,我们并没有进行计算在内,因此,修改奇数位的代码为:
for(int j = 0;j<5;j++)
{
if(i > 2) //当且仅当长度大于2时,存在偶数位为0的情况
{
for(int k = ll;k<=rr;k++)
{
q[m++] = q[k] + (j*2+1) * temp;
}
}
for(int k = l;k<=r;k++)
q[m++] = q[k] + (j*2+1) * temp;
}
ll = r + 1,l = r+1,r = m-1,rr = m - 1;
因此,最终代码为:
#include <iostream>
using namespace std;
const int N = 1e7+10;
int q[N];
int main(){
int n;
cin>>n;
int m = 1,temp = 1;
int l = 0,r = 0;
int ll,rr;
for(int i = 1;i<8;i++)
{
if(i%2==1)
{
for(int j = 0;j<5;j++)
{
if(i > 2)
{
for(int k = ll;k<=rr;k++)
{
q[m++] = q[k] + (j*2+1) * temp;
//cout<<q[m-1]<<endl;
}
}
for(int k = l;k<=r;k++)
q[m++] = q[k] + (j*2+1) * temp;
}
ll = r + 1,l = r+1,r = m-1,rr = m - 1;
}
else{
for(int j = 1;j<5;j++)
{
for(int k = l;k<=r;k++)
q[m++] = q[k] + (j*2) * temp;
}
l = r+1,r = m-1;
}
temp = temp * 10;
}
long long res = 1;
while(q[res] <= n)
{
//cout<<q[res]<<" ";
res++;
}
//cout<<endl;
cout<<res-1<<endl;
return 0;
}