首页 > 代码库 > HZOI 2017 OTTFFSSEN

HZOI 2017 OTTFFSSEN

题面:

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 }
View Code

(PS:可会爆LL,要用高精度(用double会炸精度,long double不会输出QAQ))

HZOI 2017 OTTFFSSEN