BZOJ 1833: [ZJOI2010]count 数字计数

Description

问 \([L,R]\) 中0-9的个数.

Sol

数位DP.

预处理好长度为 \(i\), 最高位为 \(j\) 的数位之和.

然后从上往下计算,不要忘记往下走的同时要把高位的贡献加上去..

Code

/**************************************************************
    Problem: 1833
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:40 ms
    Memory:1396 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
 
typedef long long LL;
const int N = 65;
 
struct S {
    LL a[10];
    S(LL v=0) { for(int i=0;i<10;i++) a[i]=v; }
}f[N][10][2];
 
S operator + (const S &a,const S &b) {
    S c;for(int i=0;i<10;i++) c.a[i]=a.a[i]+b.a[i];
    return c;
}
S operator - (const S &a,const S &b) {
    S c;for(int i=0;i<10;i++) c.a[i]=a.a[i]-b.a[i];
    return c;
}
S operator * (const S &a,const LL &b) {
    S c;for(int i=0;i<10;i++) c.a[i]=a.a[i]*b;
    return c;
}
void Print(const S &a) { for(int i=0;i<9;i++) cout<<a.a[i]<<" ";cout<<a.a[9]; }
 
LL l,r;
LL pow10[N];
 
inline LL Pow(LL a,LL b,LL r=1) { return pow10[b]; }
void init() {
    pow10[0]=1;
    for(int i=1;i<=15;i++) pow10[i]=pow10[i-1]*10LL;
     
    for(int i=0;i<10;i++) {
        f[1][i][0]=f[1][i][1]=f[1][i-1][0];
        f[1][i][0].a[i]+=1,f[1][i][1].a[i]+=1;
    }
    for(int l=2;l<=14;l++) {
        f[l][0][0]=f[l-1][9][0];
        f[l][0][1]=f[l-1][9][1];
        f[l][0][1].a[0]+=Pow(10,l-1);
        for(int i=1;i<10;i++) {
            f[l][i][0]=f[l][i-1][0]+f[l-1][9][1];
            f[l][i][0].a[i]+=Pow(10,l-1);
            f[l][i][1]=f[l][i-1][1]+f[l-1][9][1];
            f[l][i][1].a[i]+=Pow(10,l-1);
        }
    }
     
//  for(int l=1;l<=5;l++) for(int i=0;i<10;i++) {
//      cout<<l<<":"<<i<<endl;
//      Print(f[l][i][0]),Print(f[l][i][1]);
//      cout<<"-------------------------------"<<endl;
//  }
}
S calc(LL x) {
    LL g=0,nn;S r,t;
    for(int i=13;~i;i--) {
        if(x/pow10[i]) {
            nn=(LL)(x/pow10[i])*pow10[i];
            r=r+t*nn;
             
            t.a[x/pow10[i]]++;
             
            r=r+f[i+1][x/pow10[i]-1][g];
            g=1;
//          cout<<i+1<<" "<<x/pow10[i]-1<<" "<<g<<endl;
        }else {
            if(g) t.a[0]++;
        }x%=pow10[i];
//      cout<<i<<" ";Print(r);
    }return r;
}
int main() {
    init();
     
    cin>>l>>r;
     
    S ans1=calc(r+1);
    S ans2=calc(l);
     
//  Print(ans1),Print(ans2);
    Print(ans1-ans2);
    return 0;
}

  

posted @ 2016-12-15 15:41  北北北北屿  阅读(137)  评论(0编辑  收藏  举报