题意 :计算 m到n区间中的数一共包含了多少个0.
思路:定义DP状态dp[a][b][c]表示a位数,开头为b ,含有c个0的数的个数。
转移状态:
if(b>=1)
dp[a][b][c]+=dp[a-1][z][c] (0=<z<=9)
else
dp[a][b][c]+=dp[a-1][z][c-1] (0=<z<=9)
对数字进行DP预处理,然后对于每个低于n或m的数字进行去除前导0的特殊处理,最后特判m即可。
本题WA在了两个地方 :
1、1000-1050 这里面如果直接算小于第三位数字的数那就直接跳过了,但实际上要记录,下一位往后的数字大小等量的0.
2、0 0这种情况要进行特判。
3、因为无符号整型,所以要用long long 。
#include <iostream>
#include <cstdio>
#include <cstring>
typedef long long LL;
using namespace std;
LL dp[22][12][22];
int len[3];
int num[3][22];
LL bit[19];//预处理10的几次方
LL nn[19];//处理m的i位往后数字组成的数是多少
LL nn1[19];//处理n的i位往后的数字组成的数是多少
LL m,n;
void work()
{
dp[0][0][0]=1;
for(int i=1; i<=20; i++)
{
for(int j=0; j<=9; j++)
for(int k=0; k<=i; k++)
{
for(int z=0; z<=9; z++)
{
if(j>=1)
{
dp[i][j][k]+=dp[i-1][z][k];
}
else
{
// if(k>=1)
dp[i][j][k]+=dp[i-1][z][k-1];
}
}
}
}
}
void cal(int t)
{
len[t]=0;
if(t==0)
{
while(m)
{
//cout<<m<<endl;
num[t][++len[t]]=m%10;
nn[len[t]]=nn[len[t]-1]+num[t][len[t]]*bit[len[t]];
m/=10;
}
}
else
{
while(n)
{
num[t][++len[t]]=n%10;
nn1[len[t]]=nn1[len[t]-1]+num[t][len[t]]*bit[len[t]];
n/=10;
}
}
}
LL solve()
{
LL res=0;
LL sum=0;
for(int i=len[0]; i>0; i--)
{
if(num[0][i]!=0)
{
res+=(nn[i])*sum;
sum=0;
}
else
{
sum++;
}
for(int j=0; j<num[0][i]; j++)
{
if((j==0)&&(i==len[0])) continue;
for(int l=0; l<=i; l++)
{
res+=(LL)dp[i][j][l]*l;
}
}
}
for(int i=len[0]-1; i>0; i--)
{
for(int j=1; j<=9; j++)
{
for(int z=0; z<i; z++)
{
res+=(LL)dp[i][j][z]*z;
}
}
}
LL res1=0;
LL sum1=0;
for(int i=len[1]; i>0; i--)
{
if(num[1][i]!=0)
{
res1+=(nn1[i])*sum1;//这里处理1050这种情况
sum1=0;
}
else
{
sum1++;
}
for(int j=0; j<num[1][i]; j++)
{
if((j==0)&&(i==len[1])) continue;
for(int l=0; l<=i; l++)
{
res1+=(LL)dp[i][j][l]*l;
}
}
}
for(int i=len[1]-1; i>0; i--)//特殊处理小于len的
{
for(int j=1; j<=9; j++)
{
for(int z=0; z<i; z++)
{
res1+=(LL)dp[i][j][z]*z;
}
}
}
return res1-res;
}
LL check()
{
LL cnt=0;
for(int i=1; i<=len[1]; i++)
{
if(num[1][i]==0)
{
cnt++;
}
}
return cnt;
}
int main()
{
freopen("in.txt","r",stdin);
memset(dp,0,sizeof(dp));
memset(num,0,sizeof(num));
memset(nn,0,sizeof(nn));
memset(nn1,0,sizeof(nn1));
work();
bit[1]=1;
for(int i=2;i<=17;i++)
{
bit[i]=bit[i-1]*10;
}
while(~scanf("%lld%lld",&m,&n))
{
LL ans1=0;
if((m==0)&&(n==0))
{
printf("1\n");
continue;
}
if((m==-1)) break;
if(m==0)
{
num[0][1]=0;
len[0]=1;
ans1++;
}
else
{
cal(0);
}
cal(1);
ans1+=solve()+check();
printf("%lld\n",ans1);
}
return 0;
}