• 【数学】8.30题解-count数页码


    count

    洛谷p1836

    题目描述

    一本书的页码是从 1-n 编号的连续整数: 1, 2, 3, ... , n。请你求出全部页码中
    所有单个数字的和,例如第 123 页,它的和就是 1+2+3=6。

    输入输出

    输入
    一行为 n(1 <= n <= 10^9)。
    输出
    一行,代表所有单个数字的和。

    样例

    样例输入

    3456789
    

    样例输出

    96342015
    

    说明

    时间限制 1s/testcase
    空间限制 32MB

    思路

    鉴于 n 可以达到 10^9,直接模拟是不可取的
    逐位递推,发现规律.

    1. 对于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;
    	}
    }
    
    1. 可以先用暴力算出n=1e1,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9时的答案
    2. 对于大于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;
    }
    
  • 相关阅读:
    Android 面试题(答案最全)
    Android Studio导入github下载的工程
    Android清除本地数据缓存代码
    内存缓存LruCache实现原理
    OD调试器调试Delphi程序按钮事件断点方法
    OllyDBG找到按钮的处理函数
    delphi中Record 和Packed Record的区别
    这些年,我们自己换的滤芯
    大众车机天宝187A Hack笔记
    Delphi中DLL的创建和使用
  • 原文地址:https://www.cnblogs.com/bbqub/p/7454266.html
Copyright © 2020-2023  润新知