题目
pata1049
题目思路
对于任一数字如654321,在计算1的数量时可以将其拆分为,1至60000,600001至650000,650001至654000,654001至654300,654301至654320,654321这几部分来计算,由于高位数字均没有1,则可简化为1至600000,1至50000,1至4000,1至300,1至20,1中1的数量。因此,可以先计算从0到9、99、999等里1的数量s[n],而对于首数字大于1的数,例如30,300,3000之类可用3*s[i]+10的p次方(p为30,300,3000里0的数量,即用于表示1开头的数字数)。对于首数字为1的数,拆分时需要注意在总数中加上1后所跟数字的数值+1,用以表示在拆分时忽略掉的首位的1。
参考代码
#include<iostream>
#include<cstring>
using namespace std;
int count(char c,int p,int n,int s[]);
int change(char c[]);
int main()
{
char c[12];
int s[12];
int p=1,t=0,n=0;
s[1]=1;
for(int i=2;i<12;i++)
{
p*=10;
s[i]=s[i-1]*10+p;//s[i]表示从0到i个9之间有多少个1
}
scanf("%s",c);
p=1;
for(int i=0;i<strlen(c)-1;i++)//位数
{
p*=10;
n+=1;
}
for(int i=0;i<strlen(c);i++)
{
t+=count(c[i],p,n,s);
if(c[i]=='1')
t+=change(c)%p+1;
p/=10;
n-=1;
}
printf("%d",t);
return 0;
}
int count(char c,int p,int n,int s[])//从0到c*10的n次方之间有多少1
{
int t=0;
if(c>'1')
t+=p;
if(n>0)
t+=(c-'0')*s[n];
return t;
}
int change(char c[])
{
int a=0,p=1;
for(int i=strlen(c)-1;i>=0;i--)
{
a+=(c[i]-'0')*p;
p*=10;
}
return a;
}