习题:数字计数(数位DP+差分)

题目

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

输入格式

仅包含一行两个整数 a,b含义如上所述。

输出格式

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

思路

很明显如果直接求[a,b]比较难,因为要考虑到各种各样的进位问题
但是如果求[1,n]就比较简单了,于是差分的想法自然而然就出现了
接着考虑怎么求[1,n],很明显是有一个周期的
For example
如果针对个位,就是9个数为一个周期1,2,3,4,5,6,7,8,9,
接着我们一位一位地考虑,就可以求出每一个数的贡献
最后在单独考虑0就行了
记得开longlong,作者因为没开long long错了N次

代码

#include<iostream>
#include<cstring>
using namespace std;
#define int long long
int a,b;
int n[25];
int f[25];
int t[25];
int dp[10];//表示数字i出现了多少次
void solve(int x,int fl)
{
	int len=0;
	memset(n,0,sizeof(n));
	while(x)
	{
		n[++len]=x%10;
		x/=10;
	}
	while(len)
	{
		for(int i=0;i<=9;i++)
			dp[i]+=f[len-1]*n[len]*fl;
		for(int i=0;i<n[len];i++)
			dp[i]+=t[len-1]*fl;
		long long te=0;
		for(int i=len-1;i>=1;i--)
			te=te*10+n[i];
		dp[n[len]]+=(te+1)*fl;
		dp[0]-=t[len-1]*fl;
		len--;
	}
}
signed main()
{
	cin>>a>>b;
	t[0]=1;
	for(int i=1;i<=13;i++)
	{
		f[i]=f[i-1]*10+t[i-1];
		t[i]=t[i-1]*10;
	}
	solve(a-1,-1);
	solve(b,1);
	for(int i=0;i<=9;i++)
		cout<<dp[i]<<" ";
	return 0;
}
posted @ 2019-09-29 13:54  loney_s  阅读(151)  评论(0)    收藏  举报