bzoj1833: [ZJOI2010]count 数字计数 && codevs1359 数字计数
这道题也是道数位dp 因为0有前导0这一说卡了很久 最后发现用所有位数减1~9的位数就okay.....orzczl大爷 其他就跟51nod那道统计1出现次数一样啦
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL f[15][10][10],w[15],cur=15,ans1[15],ans2[15]; void prepare(){ w[1]=1; for(int i=2;i<=12;i++) w[i]=w[i-1]*10; for(int i=0;i<=9;i++) f[1][i][i]=1; for(int i=2;i<=12;i++) for(int j=0;j<=9;j++) for(int k=0;k<=9;k++){ for(int z=0;z<=9;z++) f[i][j][k]+=f[i-1][z][k]; if(j==k) f[i][j][k]+=w[i]; } } void work1(LL n){ int cur=12; if(!n){ans1[0]=1; return ;} while(w[cur]>n) cur--; LL tot=1; for(int i=1;i<cur;i++) tot+=(w[i+1]-w[i])*i; tot+=(n-w[cur]+1)*cur; LL v=n/w[cur]; for(int i=0;i<=9;i++) for(int j=0;j<v;j++) ans1[i]+=f[cur][j][i]; ans1[v]=ans1[v]+n%w[cur]+1; n=n%w[cur]; for(int i=cur-1;i;i--){ v=n/w[i]; for(int j=1;j<=9;j++) for(int k=0;k<v;k++) ans1[j]+=f[i][k][j]; ans1[v]=ans1[v]+n%w[i]+1; n=n%w[i]; } //printf("%lld %lld\n",tot,ans1[0]); for(int i=1;i<=9;i++) tot-=ans1[i]; ans1[0]=tot; } void work2(LL n){ int cur=12; if(!n){ans2[0]=1; return ;} while(w[cur]>n) cur--; LL tot=1; for(int i=1;i<cur;i++) tot+=(w[i+1]-w[i])*i; tot+=(n-w[cur]+1)*cur; LL v=n/w[cur]; for(int i=1;i<=9;i++) for(int j=0;j<v;j++) ans2[i]+=f[cur][j][i]; ans2[v]=ans2[v]+n%w[cur]+1; n=n%w[cur]; for(int i=cur-1;i;i--){ v=n/w[i]; for(int j=1;j<=9;j++) for(int k=0;k<v;k++) ans2[j]+=f[i][k][j]; if(v) ans2[v]=ans2[v]+n%w[i]+1; n=n%w[i]; } //printf("%lld %lld\n",tot,ans2[0]); for(int i=1;i<=9;i++) tot-=ans2[i]; ans2[0]=tot; } int main() { prepare(); work1(read()-1); work2(read()); for(int i=0;i<=9;i++){ printf("%lld",ans2[i]-ans1[i]); if(i!=9) printf(" "); } return 0; }