bzoj 1833: [ZJOI2010]count 数字计数(数字0-9的个数)

1833: [ZJOI2010]count 数字计数

Time Limit: 3 Sec   Memory Limit: 64 MB
Submit: 3528   Solved: 1553
[ Submit][ Status][ Discuss]

Description

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

Input

输入文件中仅包含一行两个整数a、b,含义如上所述。

Output

输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

Sample Input

1 99

Sample Output

9 20 20 20 20 20 20 20 20 20


经典题,数位dp,求0的个数可以最后用数字总数与1-9数字个数相减

#include<stdio.h>
#define LL long long
char str[20];
LL len, dp[10][20], ans1[15], ans2[15];
LL Sech(int x, int t, int flag);
LL Zero(LL c);
LL Jud(LL k, int x);
LL Pow(int k)
{
	LL sum = 1;
	while(k--)
		sum *= 10;
	return sum;
}
int main(void)
{
	LL a, i, j, b, sum1, sum2;
	for(i=1;i<=9;i++)
		for(j=0;j<=19;j++)
			dp[i][j] = -1;
	while(scanf("%lld%lld", &a, &b)!=EOF)
	{
		sum1 = sum2 = 0;
		for(i=1;i<=9;i++)
		{
			ans1[i] = Jud(b, i), ans2[i] = Jud(a-1, i);
			sum1 += ans1[i], sum2 += ans2[i];
		}
		printf("%lld", Zero(b)-sum1-Zero(a-1)+sum2);
		for(i=1;i<=9;i++)
			printf(" %lld", ans1[i]-ans2[i]);
		printf("\n");
	}
	return 0;
}

LL Zero(LL c)		//统计有多少个数字,那么0的个数就是数字总数-∑数字1-9个个数
{
	int len;
	if(c==0)  return 0;
	LL temp = c, sum = 0;
	for(len=0;c>0;c/=10)
		len++;
	sum += (temp-Pow(len-1)+1)*len;
	while(--len)
		sum += 9*Pow(len-1)*len;
	return sum;
}
LL Jud(LL k, int x)
{
	int len = 0;
	while(k)
	{
		str[++len] = k%10+'0';
		k /= 10;
	}
	str[len+1] = '\0';
	return Sech(x, len, 1);
}

LL Sech(int x, int len, int flag)
{
	int u, i, j;
	LL k, ans;
	if(len==0)
		return 0;
	if(flag==0 && dp[x][len]!=-1)
		return dp[x][len];
	u = flag? str[len]-'0':9;
	ans = 0;
	for(i=0;i<=u;i++)
	{
		if(i==x)
		{
			if(flag && i==u)
			{
				k = 0;
				for(j=len-1;j>=1;j--)
					k = k*10+str[j]-'0';
				ans += ++k;
			}
			else
				ans += Pow(len-1);
		}
		ans += Sech(x, len-1, flag && i==u);
	}
	if(flag==0)
		dp[x][len] = ans;
	return ans;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值