P2602 [ZJOI2010]数字计数

偷得题面

1522713-20191028094208523-655738802.png

设f[i]代表第i位上不算前导零每个数出现多少次

比如54321

首先是5,,5在万位上,那么个十百千位每个数都会出现至少5*f[bit]次,然后万位上,5以下的数都会出现,然后以此类推

最后加完所有位之后,在处理4321这样的跑不满的零位就好了qwq

代码

#include <bits/stdc++.h>
#define int long long
using namespace std ;
int a , b ;
int ten[15] , f[15] ;
int cnta[15] , cntb[15] , num[10] ;
void work(int x ,int cnt[])  {
    for(int i = 0 ; i < 10 ; i ++) num[i] = 0 ;
    int len = 0 ;
    while(x) {//拆数 
        num[++len] = x%10 ;
        x = x / 10 ; 
    }
    for(int i = len ; i >= 1 ; i --) {
        for(int j = 0 ; j <= 9 ; j ++) {
            cnt[j] += f[i-1] * num[i] ; //第i位之后的每位每个数数都会出现i次 
        }
        for(int j = 0 ; j < num[i] ; j ++) {
            cnt[j] += ten[i-1] ;//第i位是x,那么在x之前的都会在出现10^(bit-1)次 
        }
        //--------以上只是处理A000000....00这亚子----------//
        //--------以下处理零位--------// 
        int num2 = 0 ;
        for(int j = i-1 ; j >= 1 ; j --) {
            num2 = num2 * 10 + num[j] ;//加上零位 
        }
        cnt[num[i]] += num2 + 1 ;// num2是零位,1是最高位
        cnt[0] -= ten[i-1] ;//清除前导零 
    }
}  
signed main () {
    scanf("%lld%lld",&a,&b) ;
    ten[0] = 1 ;//10的阶乘,每一位代表多少 
    for(int i = 1 ; i <= 15 ; i ++) {
        f[i] = f[i-1] * 10 + ten[i-1] ;//在第i位有数字的时候,每个数码有多少个 
        ten[i] = 10*ten[i-1] ; 
    }
    work(a-1,cnta) ;//work(0-x的各数位,统计答案的数组) 
    work(b,cntb) ;
    for(int i = 0 ; i <= 9 ; i ++) printf("%lld ",cntb[i] - cnta[i]) ;
    return 0 ;
} 

举个栗子: 32345

首先 是 5f[0] ,然后4f[1] (也就是4个一位数所有的数,因此当前位数4是没有算上的),然后是3*f[2] (也就是4个两位数所有的数,因此当前位数3是没有算上的)....以此类推

然后我们成功的处理完len-1位(y因为这些位数一定是合法的)后,开始考虑len位,首先,num[len]-1个ten[i-1]次(y因为最后一位不算零头也只能出现这些),然后在填上零头就好了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值