luogu_2602【题解】数位DP 数字计数
题目:https://www.luogu.org/problemnew/show/P2602
大意:给定两个正整数a和b,求在[a,b]中的所有整数中,每个数(0-9)各出现了多少次。
题面给的很明确。
那么怎么求[a,b]区间的呢。
可以为 ans[1,b] - ans[1,a-1].
区间相减。
求1到N的就比较简单了。
见代码注释。
代码如下:
#include<bits/stdc++.h> #define ll long long using namespace std; ll a,b,m,ans[5][1010]; int main() { scanf("%lld%lld",&a,&b); a--;//自减 for(int i=0;i<=9;i++){//1到a-1 int x=i; m=1; while(m<=a){ ll xx=a/(m*10),now=a/m%10,zz=a%m; //now为当前的数位,xx为左边的数,zz为右边的数。 //如AABCC,now为B,xx为AA,zz为CC if(x){//x大于0时候 if(now>x) ans[2][i]+=(xx+1)*m; //now大于x,所有的比xx小的开头的都可以(包括0) if(now==x) ans[2][i]+=xx*m+zz+1; //now等于x,所以为xx*m+所有zz,和自己。 if(now<x) ans[2][i]+=xx*m; //now小于x,所以只有xx个x,没有0 } else{//开头为0 if(now) ans[2][i]+=xx*m; else ans[2][i]+=(xx-1)*m+zz+1; } m*=10; } } for(int i=0;i<=9;i++){ int x=i; m=1; while(m<=b){ ll xx=b/(m*10),now=b/m%10,zz=b%m; if(x){ if(now>x) ans[1][i]+=(xx+1)*m; if(now==x) ans[1][i]+=xx*m+zz+1; if(now<x) ans[1][i]+=xx*m; } else{ if(now) ans[1][i]+=xx*m; else ans[1][i]+=(xx-1)*m+zz+1; } m*=10; } } for(int i=0;i<=9;i++) printf("%lld ",ans[1][i]-ans[2][i]); system("pause"); return 0; }