TOJ 1183 The Counting Problem 数位dp

http://acm.tju.edu.cn/toj/showp1183.html

题意:从a写到b,问每个数字各写了几次。

分析:昨天做了一道how many 0's,这题算是拓展。考虑从0..a。1到9是一样的,如果目前考虑的是digit,枚举每位,左边填0..x-1,则右边随便填(10^右边长度),左边填x,如果a的当前位大于digit,那么右边还是随便填,如果等于,只能填0..右边最大值,如果大于则没有。而0不一样在于不能作为一个数的第一位,所以左边只能填1..x-1,还有如果目前枚举的是最高位则不能填0。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 #define debug 0
 7 int beg, end;
 8 int d[20];
 9 int ans1[15], ans2[15];
10 void cal(int x, int ans[])
11 {
12     for (int i = 0; i < 10; i++) ans[i] = 0;
13     if (x == -1) return;
14     if (x == 0){
15         ans[0] = 1;
16         return;
17     }
18     int len = 0;
19     int xx = x;
20     while(x){
21         d[len++] = x % 10;
22         x /= 10;
23     }
24     x = xx;
25     for (int digit = 1; digit <= 9; digit ++){
26         int sum = 0, res = x/10, cnt = 0, exp = 1;  //res为当前位的左边,cnt为右边,exp为右边随便填的总数
27         for (int i = 0; i < len; i++){
28             sum = sum + res * exp;           //左边填0..res-1,右边随便填
29             if (digit < d[i]) sum = sum + exp;    //如果小于,左边填res,右边随便填
30             else if (digit == d[i]) sum = sum + cnt+1;  //相等,即左边到当前位都是在最高的情况,右边只能填0..cnt
31 
32             if (debug){
33                 if (digit == 4) printf("%d\n",sum);
34             }
35             cnt = cnt + d[i] * exp;
36             exp *= 10;
37             res /= 10;
38         }
39         ans[digit] = sum;
40     }
41     int sum = 1, res = x/10, cnt = 0, exp = 1;
42     for (int i = 0; i < len; i++){
43         if (res > 0) sum = sum + (res-1) * exp;    //单独算为0的情况,一个是左边从1开始,还有一个是最高位不能填0
44         if (d[i]) {
45             if (i != len-1) sum = sum + exp;
46         }
47         else sum = sum + cnt + 1;
48         cnt = cnt + d[i] * exp;
49         exp *= 10;
50         res /= 10;
51     }
52     ans[0] = sum;
53 }
54 int main()
55 {
56     while(scanf("%d %d", &beg, &end))
57     {
58         if (beg == 0 && end == 0) break;
59         if (beg > end) swap(beg, end);
60         cal(beg-1, ans1);
61         cal(end, ans2);
62         if (debug) for (int i = 0; i < 10; i++) printf("%d %d\n", ans1[i], ans2[i]);
63         for (int i = 0; i < 10; i++) printf("%d%c", ans2[i]-ans1[i], i==9? '\n': ' ');
64     }
65     return 0;
66 }

 

posted @ 2014-08-29 17:46  james47  阅读(134)  评论(0编辑  收藏  举报