count
题目描述
一本书的页码是从 1-n 编号的连续整数: 1, 2, 3, ... , n。请你求出全部页码中
所有单个数字的和,例如第 123 页,它的和就是 1+2+3=6。
输入输出
输入
一行为 n(1 <= n <= 10^9)。
输出
一行,代表所有单个数字的和。
样例
样例输入
3456789
样例输出
96342015
说明
时间限制 1s/testcase
空间限制 32MB
思路
鉴于 n 可以达到 10^9,直接模拟是不可取的
逐位递推,发现规律.
- 对于10^7以内的数据,直接模拟暴力可以过
for(int i=1; i<=n; i++)
ans+=solve(i);
inline int solve(int x) {
int an=0;
while(x) {
an=an+x%10;
x/=10;
}
}
- 可以先用暴力算出n=1e1,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9时的答案
- 对于大于1e7的数据我们可以逐位来算
举个较小的例子:7654
第一位:7 ;
(1) 则1~6一定都在第一位出现了1e3次;
(2) 7出现了654+1次
(3) 再加上7*ans(1e3时的答案)
(4) 然后去掉这一位,原本的第二位,变成了现在的第一位
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<ctime>
using namespace std;
typedef long long ll;
int n;
ll ans;
ll a[20];
inline int solve(int x) {
int an=0;
while(x) {
an=an+x%10;
x/=10;
}
return an;
}
int main() {
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&n);
if(n<=1e7) {
for(int i=1; i<=n; i++)
ans+=solve(i);
printf("%d",ans);
return 0;
}
a[1]=45;
a[2]=900;
a[3]=13500;
a[4]=180000;
a[5]=2250000;
a[6]=27000000;
a[7]=315000000;
a[8]=3600000000LL;
if(n<1e8) {
ll temp=1e7,pos=7;
while(pos) {
int k1=n/temp;
k1--;
ans+=(ll)temp*(ll)k1*(ll)(k1+1)/2;
ans+=(ll)(k1+1)*(ll)a[pos];
ans+=(ll)(k1+1)*(ll)(n%temp+1);
n%=temp;
temp/=10;
pos--;
}
ans+=(ll)n*(ll)(n+1)/2;
printf("%lld",ans);
return 0;
}
if(n<1e9) {
ll temp=1e8,pos=8;
while(pos) {
int k1=n/temp;
ans+=(ll)temp*(ll)k1*(ll)(k1-1)/2; //(1)
ans+=(ll)(k1)*(ll)a[pos]; //(3)
ans+=(ll)(k1)*(ll)(n%temp+1); //(2)
n%=temp; //(4)
temp/=10; //(4)
pos--; //(4)
}
ans+=(ll)n*(ll)(n+1)/2;
printf("%lld",ans);
return 0;
}
return 0;
}