[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 }