2602 数字计数
一般像这种数位DP,都是像这样给定区间,对区间进行操作,对于这道题的题意不难理解,就是统计区间0~9的个数
看不出来和动态规划有什么关系
这道题很难推出来递推公式,因为很难想到怎么求第几位的数字是多少,因为不能有前导零
f[i]表示在有i位数字的情况下,每个数字有多少个,如果不考虑前导0,你会发现对于每一个数,他的数量是相等的,也就是f[i]=f[i-1]×10+10i-1
对于DP这个东西,最重要的其实就一点,推状态,什么是状态?是大问题的子问题,对于DP很重要的就是无后效性,问题可以拆分,并且答案具有一定的规律,这样就能DP了
数位DP最重要的就是把一整个数字拆分成一位一位的单独来看,所以对于数位DP,他的子问题就是求每一位答案求解
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
const int SIZE=30;
ll a,b;
ll log[SIZE];//计算10的次幂
ll f[SIZE];//代表在有i位数字,每一位数字有多少个
ll cnta[SIZE],cntb[SIZE];
void sol(ll x,ll *cnt)
{
ll num[20]={0};//转换数位
int len=0;
while(x)
{
num[++len]=x%10;
x=x/10;
}
for(int i=len;i>=1;i--)//枚举位数
{
for(int j=0;j<=9;j++)//求代表数字个数
cnt[j]+=f[i-1]*num[i];//A*f[i-1]
for(int j=0;j<num[i];j++)
cnt[j]+=log[i-1];
ll num2=0;
for(int j=i-1;j>=1;j--)
{
num2=num2*10+num[j];//计算前导零的情况
//10*i-1*i-2*i-3*i-4
}
cnt[num[i]]+=num2+1;
cnt[0]-=log[i-1];
}
}
int main()
{
cin>>a>>b;
log[0]=1;
for(int i=1;i<=15;i++)
{
f[i]=f[i-1]*10+log[i-1];//计算f数组
log[i]=10*log[i-1];//计算10次幂
}
sol(a-1,cnta);
sol(b,cntb);
for(int i=0;i<=9;i++)
cout<<cntb[i]-cnta[i]<<" ";
return 0;
}