题意:给两个数l,r,求[l,r]区间内这么多数包含多少个"0" "1" "2"..."9"。 比如[1 10] 除了"1"有2个,其余数字均只有1个。
思路:数的范围为1e8,又是数的统计,一看就是数位dp。设dp[ i ] [ pos ] [ cnt ]为当前考虑数字为i,且当前考虑pos位,之前的位已经
有cnt个数字i,之后(pos+1)位与之前数位组合含数字i的个数。那么除了数字“0”需要考虑前导零之外,其他的正常求就可以了。详见代码:
/********************************************************* file name: poj2282.cpp author : kereo create time: 2015年01月22日 星期四 19时06分00秒 *********************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int N=10; const int MAXN=100000+50; const int inf=0x3fffffff; const double eps=1e-8; const int mod=100000000+7; #define L(x) (x<<1) #define R(x) (x<<1|1) #define PII pair<int, int> #define mk(x,y) make_pair((x),(y)) int n,m; int bit[N]; ll num[N],ans1[N],ans2[N],dp[N][N][N]; //dp[i][pos][cnt]表示当前考虑的是i,考虑当前位置pos,之前i的个数为cnt ll dfs(int cur,int pos,int cnt,int pre,int flag){ if(pos == -1) return cnt; if(flag && dp[cur][pos][cnt]!=-1){ if(cur != 0) return dp[cur][pos][cnt]; else if(pre) return dp[cur][pos][cnt]; } ll ans=0; int x=flag ? 9 : bit[pos]; for(int i=0;i<=x;i++){ if(cur == 0) ans+=dfs(cur,pos-1,cnt+(pre && i == cur),pre || i,flag || i<x); else ans+=dfs(cur,pos-1,cnt+(i == cur),pre || i,flag || i<x); } if(flag){ if(cur != 0) return dp[cur][pos][cnt]=ans; else if(pre) return dp[cur][pos][cnt]=ans; } return ans; } void solve(int x){ int len=0; if(!x) bit[len++]=x; while(x){ bit[len++]=x%10; x/=10; } for(int i=0;i<10;i++) num[i]=dfs(i,len-1,0,0,0); } int main(){ while(~scanf("%d%d",&n,&m) && n+m){ memset(dp,-1,sizeof(dp)); if(n>m) swap(n,m); solve(n-1); for(int i=0;i<10;i++) ans1[i]=num[i]; solve(m); for(int i=0;i<10;i++) ans2[i]=num[i]; for(int i=0;i<10;i++){ if(i == 0) printf("%lld",ans2[i]-ans1[i]); else printf(" %lld",ans2[i]-ans1[i]); } printf("\n"); } return 0; }
时间: 2024-11-18 20:55:03