UVA1640 统计问题 The Counting Problem
题意
统计正整数 中 每个数码出现的次数。
分析
其实就是计算两次 中每个数码 出现的次数,前缀和相减就是答案。
我们设 表示 中数码 出现的次数,先把数 按位拆分,设共有 位,个位到第 位分别存在 中,为了方便后面的计算,再求出 表示 的第 位到个位组成的数。
然后开始求答案 ,众所周知, 比较特殊,于是我们把 单独提出来处理,先解决当 时怎么做。
设 表示 的第 位之前全部填 时第 位的可能的数码 的个数,特别的,当 时,也认为有一个虚拟的第 位填了最大的限制。
因此当 时, 为 。
然后写 。我们把统计第 位分成第 位和第 位来算:
-
求第 位填 时的数的个数:若 ,这一位填 时前面的位已经固定,后面的则可以为 共 种数;若 ,则 位都填了最大值,剩下的位可以填 种数;若 ,则不可能填。
-
求第 位填 时的数的个数:若第 位填 ,则后面的位子填的 的个数就是 ;若第 位填 ,则此时后面的填法时没有限制的,设 表示 中的所有数的数码 的个数的总和,则答案为 。
对于 的情况,最高位不能填 ,只要求出第 位填 时的答案和所有 位数中 的个数再相加就是答案。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=10;
ll dp[N][N],m10[N]={1},a[N],b[N];
ll dfs(int p,int num){
if(p==0)
return 0;
ll ans=0;
if(num<a[p])
ans+=m10[p-1];
else if(num==a[p])
ans+=b[p-1]+1;
ans+=dp[p-1][num]*a[p];
ans+=dfs(p-1,num);
return ans;
}
ll ask(ll x,int num){
if(x<10)
return num<=x;
int n=0;
while(x){
a[++n]=x%10;
x/=10;
b[n]=a[n]*m10[n-1]+b[n-1];
}
ll ans=0;
if(num==0){
ans=dp[n-1][num]*(a[n]-1);
ans+=dfs(n-1,num);
ans+=ask(m10[n-1]-1,num);
}
else
ans=dfs(n,num);
return ans;
}
int main(){
for(int i=0;i<=9;i++)
dp[1][i]=1;
for(int i=1;i<=9;i++)
m10[i]=m10[i-1]*10;
for(int i=2;i<=9;i++)
for(int j=0;j<=9;j++)
dp[i][j]=m10[i-1]+dp[i-1][j]*10;
ll x,y;
while(cin>>x>>y&&x&&y){
if(x<y)
swap(x,y);
for(int i=0;i<9;i++)
cout<<ask(x,i)-ask(y-1,i)<<" ";
cout<<ask(x,9)-ask(y-1,9)<<endl;
}
return 0;
}
注意输出不能多行末空格。

浙公网安备 33010602011771号