题面:
OTTFFSSEN
One Two Three Four Five Six Seven Eight Nine……
描述
AFO已久的Aglove重新开始学数数,他励志要成为数数少年。为了避免爆零的尴尬,他决定对零这个万恶的数字视而不见。
他的老师为了调教他,就给他出了一道题:
求在区间[L,R]范围内的正整数中在十进制表示下不是0的数位的个数。
Aglove已经AFO太久太久了,况且他还要陪妹子数星星,他决定将这个光荣而伟大的任务委任给你,如果你能顺利完成,你将成为伟大的数数少年。
输入
第一行有两个整数L,R,意义如题目所述。
输出
输出题目要求的结果。
样例输入
23 233
样例输出
515
数据范围和约定
对30%的数据,L和R均不超过10^7
对60%的数据,L和R均不超过10^10
另外有20%的数据,满足L和R均为10^k的形式
对100%的数据,0<=L<=R<=2^63-1
时空限定
内存限制为 512 MB
时间限制为 1 s
一看就是数位DP。
考虑每位对答案的贡献:
以435230134为例
最高位一定没有贡献(不为零)。之后一位贡献是4*10^7,以此类推。某位不是零时(如第6位)贡献是(43523-1)*10^3+134+1(这位是零,要加1)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define LL long long 6 #define LF double 7 LF bin[30]={1},num1[30],num2[30]; 8 LF sum[30]; 9 LL l,r; 10 LL c[30]; 11 LF dp(int len) 12 { 13 LF ans=0; 14 for(int i=len-1;i>=1;i--) 15 { 16 ans+=(num1[i+1]-1)*bin[i-1]; 17 if(c[i]==0) 18 ans+=num2[i-1],++ans; 19 else 20 ans+=bin[i-1]; 21 } 22 return ans; 23 } 24 LF getsum(LL x) 25 { 26 LF ans=0,reee=0; 27 for(int i=19;i>=1;i--) 28 if(x>=bin[i]-1) 29 { 30 ans+=sum[i]; 31 reee=i; 32 x-=(bin[i]-1); 33 break; 34 } 35 ans+=(reee+1)*x; 36 return ans; 37 } 38 LF solve(LL x) 39 { 40 memset(c,0,sizeof(c)); 41 memset(num1,0,sizeof(num1)); 42 memset(num2,0,sizeof(num2)); 43 int len=0; 44 while(x) 45 { 46 c[++len]=x%10; 47 x/=10; 48 } 49 for(int i=len;i>=1;i--) 50 num1[i]=num1[i+1]*10+c[i]; 51 for(int i=1;i<=len;i++) 52 num2[i]=num2[i-1]+c[i]*bin[i-1]; 53 return dp(len); 54 } 55 void init() 56 { 57 for(int i=1;i<=19;i++) 58 sum[i]=sum[i-1]+(bin[i]-bin[i-1])*i; 59 } 60 int main() 61 { 62 for(int i=1;i<=19;i++) 63 bin[i]=bin[i-1]*10; 64 init(); 65 scanf("%lld%lld",&l,&r); 66 if(l==0) 67 l=1; 68 LF ans1=-solve(r)+solve(l-1); 69 ans1+=getsum(r)-getsum(l-1); 70 printf("%.0lf",ans1); 71 }
(PS:可会爆LL,要用高精度(用double会炸精度,long double不会输出QAQ))
时间: 2024-10-07 11:06:40