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