zoukankan      html  css  js  c++  java
  • 洛谷 P4999 烦人的数学作业

    题目链接
    这道题从下午一来就开始写,一直写到(4:00),终于写完了,累死我辣,但是做出来的感觉还是很苏服的~。
    本题思路:按位考虑+模拟
    题目大意是很好理解的,就是算从l到r的所有数中每个数的每一位数字加起来的和。
    如果你从(l)(r)这样一个个枚举的话,就是暴力了,不知道有没有分……
    思路分析:
    既然是模拟的话,就需要对这个所求有深入的理解。

    1. 可以把(l)(r)的答案转化成(0~r)的答案减去(0~l-1)的答案。(一个类似前缀和的思想)
    2. 下面只要考虑(0)(x)的答案怎么求了,我在这里说一下我按位处理的过程,代码实现很简单:
    • 对于一个数字(x),我们定义它的位数是(tot),每一位上的数字是(a[i])
    • 考虑最高位:在(0~x)的数中,最高位的数可以是(1~a[i])
      • 其中(1~a[1]-1)出现了(10^{tot-1})次,因为可以默认最高位是(1~a[1]-1)中的某一个数,然后后面(tot-1)位可以任取(0~9),一共是(10^{tot-1})个数((0~999……)),所以答案加上(sumlimits_{j=1}^{j<a[1]} j*(10^{tot-1}))
      • (a[i])出现了(x-a[i]*10^{tot-1}+1)次(就是x去掉最高位剩下的数+1),就是默认以它为最高位的时候,后面(tot-1)位可以是(0)(x-a[i]*10^{tot-1}),答案加上
        (a[i]*(x-a[i]*10^{tot-1}+1))
      • 举个例子:当(x=4321)的时候,最高位是(4),这一位对答案的贡献就是(1*1000+2*1000+3*1000+4*322),分别对应(1000~1999,2000~2999,3000~3999,4000~4321)这些数最高位对答案的贡献。
    • 考虑最低位:最低位的数可以是(1~9)
      • 其中1~a[tot]这些数出现了(Large lfloorfrac{x}{10} floor)(+1)次(就是(x)去掉最低位剩下的数(+1)),(a[tot]+1~9)这些数出现了(Large lfloorfrac{x}{10} floor)
      • 所以最后一位的贡献就是(sumlimits_{i=1}^{i<=a[tot]}i*()(Large lfloorfrac{x}{10} floor)(+1)+sumlimits_{i=a[tot]+1}^{i<=9}i*)(Large lfloorfrac{x}{10} floor)
      • 举个例子:(1234)中最低位的贡献就是(1*124+2*124+3*124+4*124+5*123+6*123+7*123+8*123+9*123),分别对应(0001~1231,0002~1232,0003~1233,0004~1234,0005~1225,0006~1226,0007~1227,0008~1228,0009~1229)(这里的(~)是指前三位的变化,(0001~1231)指的是第四位是(1),前三位是((000、001……123))的那些数)
    • 剩下的其他位计算方法都一样:
      • 对于某一位(i),它的答案分为三部分考虑:
        • 若这一位是(1~a[i]-1),它的贡献为(x)的前(i-1)位所拼成的数加(1)再乘上(10^{tot-i})
        • 若这一位就是(a[i]),它的贡献就是(x)去掉(i)这一位后的数再(+1)
        • (a[i]+1~9)的部分,它的贡献就是(x)的前(i-1)位所拼成的数再乘上(10^{tot-i})
      • 举个例子:当(x=1234)时,我们考虑第二位和第三位的贡献:
        • (i=2)(a[i]=2)
          • (1~a[i]-1)的数只有(1),所以贡献为前(i-1)位,即(1)加上(1)再乘上(100),贡献(200),表示第1位为0或1第3、4位为(00~99)的时候的贡献。
          • (a[i]=2),贡献是(x)剩下的位(134)(+1),贡献(135),表示第1、3、4位为(000~134)时候的贡献。
          • (a[i]+1~9)的数是(3~9),每一个数贡献是这个数乘以前(i-1)位,即(1),再乘上(100),贡献(300+400+500+600+700+800+900),分别对应着第(1)位为(0)(3、4)位为(00~99)的时候的贡献
        • (i=3)(a[i]=3)
          • (1~a[i]-1)的数是(1、2),所以贡献为前(i-1)位,即(12)加上(1)再乘上(10),贡献(130),表示第1、2位和起来为00~12,第4位为(0~9)的时候的贡献。
          • (a[i]=2),贡献是(x)剩下的位(124)(+1),贡献(125),表示第1、2、4位为(000~124)时候的贡献。
          • (a[i]+1~9)的数是(4~9),每一个数贡献是这个数乘以前(i-1)位,即(12),再乘上(10),贡献(12*40+12*50+12*60+12*70+12*80+12*90),分别对应着第(1、2)位为(0~11),第(4)位为(0~9)的时候时贡献
            然后就没了
            码:
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn=110;
    const LL mod=1e9+7;
    LL cnt[maxn],a[maxn];
    LL getcnt(LL i){
    	LL ans=0;
    	while(i){
    		ans++;
    		i/=10;
    	}
    	return ans;
    }
    LL mypow(LL a,LL b){
    	LL ans=1;
    	while(b){
    		if(b&1)ans=ans*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return ans;
    }
    LL shu(LL i){
    	LL ans=0;
    	LL tot=0;
    	while(i){
    		cnt[++tot]+=i%10;
    		ans+=i%10;
    		i/=10;
    	}
    	return ans;
    }
    LL suan(LL qian,LL hou,LL res1,LL resn,LL tot){
    	LL ans=0,nowans=0;
    	ans+=res1*(hou+1);
    	for(int i=1;i<=9;i++){
    		if(i<res1)nowans+=i;
    		if(i<=resn)ans+=i*(qian+1);
    		if(i>resn)ans+=i*qian;
    	}
    	ans+=nowans*mypow(10,tot-1);
    	return ans;
    }
    LL clac(LL n){
    	if(n==0)return 0;
    	memset(a,0,sizeof(a));
    	LL tot=getcnt(n);
    	LL qian=0,hou=0,zhong=0,ans=0;
    	for(int i=tot;i>=1;i--){
    		a[i]=n%10;
    		n/=10;
    	}
    	for(int i=1;i<=tot;i++){
    		if(i>1)hou=(hou*10+a[i])%mod;
    		if(i<tot)qian=(qian*10+a[i])%mod;
    	}
    	ans+=suan(qian,hou,a[1],a[tot],tot);
    	for(int i=2;i<tot;i++){
    		qian=0;hou=0;
    		for(LL j=1;j<a[i];j++)qian+=j;
    		for(LL j=a[i]+1;j<=9;j++)hou+=j;
    		LL now=0;
    		for(int j=1;j<=tot;j++)if(i!=j)now=(now*10+a[j])%mod;
    		ans=(ans+a[i]*(now+1)%mod)%mod;
    		now=0;
    		for(int j=1;j<i;j++){
    			now=(now*10+a[j])%mod;
    		}
    		ans=(ans+qian*(now+1)%mod*mypow(10,tot-i)%mod)%mod;
    		ans=(ans+hou*now%mod*mypow(10,tot-i)%mod)%mod;
    	}
    	return ans;
    }
    LL n;
    int main(){
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++){
    		LL l,r;
    		scanf("%lld%lld",&l,&r);
    		printf("%lld
    ",(clac(r)-clac(l-1)+mod)%mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SSH连接linux的centos报The host '192.168.*.*' is unreachable
    页面格式化数值
    学习webservice之cxf(8):Spring整合CXF
    学习webservice之cxf(7):cxf自定义拦截器
    学习webservice之cxf(6):cxf内置拦截器
    学习webservice之cxf(5):cxf处理map等复杂类型
    学习webservice之cxf(4):cxf处理javabean以及复合类型
    学习webservice之cxf(3):使用webservice实现客户端
    学习webservice之cxf(1):使用cxf实现webservice(使用jdk1.8)
    学习webservice之cxf(2):使用java代码使用webservice(jdk1.8无法使用)
  • 原文地址:https://www.cnblogs.com/liu-yi-tong/p/14016038.html
Copyright © 2011-2022 走看看