[ZJOI2010]数字计数

题目大意:
  求[l,r]之间的整数中数码0~9各自出现次数。

思路:
  数位DP。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 typedef long long int64;
 5 inline int64 getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int64 x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int64 pow[]={1ll,10ll,100ll,1000ll,10000ll,100000ll,1000000ll,10000000ll,100000000ll,1000000000ll,10000000000ll,100000000000ll,1000000000000ll};
13 int64 cnt[10];
14 inline void calc(const int64 &n,const int &sgn) {
15     if(n==-1) {//如果从0开始算,那么单独一个0也要算进去(不然会被当作前导0) 
16         cnt[0]++;
17         return;
18     }
19     //以12345为例 
20     for(register int k=1;k<10;k++) {//枚举数字
21         for(register int i=1;;i++) {//枚举数位
22             int64 high=n/pow[i],low=n%pow[i-1];//高位、低位 
23             int cur=n%pow[i]/pow[i-1];//当前位(比如取了3) 
24             if(cur==k) cnt[k]+=(high*pow[i-1]+low+1)*sgn;//00300~11399+12300~12345 
25             if(cur>k) cnt[k]+=(high+1)*pow[i-1]*sgn;//00200~11299+12200~12299 
26             if(cur<k) cnt[k]+=high*pow[i-1]*sgn;//00400~11499 
27             if(pow[i]>n) break;
28         }
29     }
30     for(register int i=1;;i++) {//单独计算0
31         int64 high=n/pow[i],low=n%pow[i-1];
32         int cur=n%pow[i]/pow[i-1];
33         //都比原来少乘一个pow[i-1],因为要去掉前面全是0的情况 
34         if(cur) {
35             cnt[0]+=high*pow[i-1]*sgn;
36         } else {
37             cnt[0]+=((high-1)*pow[i-1]+low+1)*sgn;
38         }
39         if(pow[i]>n) break;
40     }
41 }
42 int main() {
43     int64 l=getint(),r=getint();
44     calc(r,1);
45     calc(l-1,-1);
46     for(register int i=0;i<9;i++) {
47         printf("%lld ",cnt[i]);
48     }
49     printf("%lld\n",cnt[9]);
50     return 0;
51 }

 

posted @ 2017-10-19 09:32  skylee03  阅读(132)  评论(0编辑  收藏  举报