洛谷 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……)\),所以答案加上\(\sum\limits_{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 \lfloor\frac{x}{10}\rfloor\)\(+1\)次(就是\(x\)去掉最低位剩下的数\(+1\)),\(a[tot]+1~9\)这些数出现了\(\Large \lfloor\frac{x}{10}\rfloor\)
    • 所以最后一位的贡献就是\(\sum\limits_{i=1}^{i<=a[tot]}i*(\)\(\Large \lfloor\frac{x}{10}\rfloor\)\(+1)+\sum\limits_{i=a[tot]+1}^{i<=9}i*\)\(\Large \lfloor\frac{x}{10}\rfloor\)
    • 举个例子:\(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\n",(clac(r)-clac(l-1)+mod)%mod);
	}
	return 0;
}
posted @ 2020-11-21 16:10  刘益通  阅读(203)  评论(2编辑  收藏  举报