BZOJ1833: [ZJOI2010]count 数字计数

BZOJ1833: [ZJOI2010]count 数字计数

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

HINT

30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。


题解Here!

一眼看出是数位$DP$。
然后也一眼看出不会做。。。
一脸无奈。。。
开始乱搞。。。
然后真的把数位$DP$搞出来了。。。
开森!
设$dp[i][j][k]$表示一个长度为$i$的数,其中最高位是$j$,$kk$这个数码一共出现的次数。
然后我们需要枚举当前位数,当前最高位填什么数,次高位填什么数,之后转移一下就好了。
转移方程长这个样:
$$dp[i][j][p]=\sum_{k=0}^9dp[i-1][k][p]$$
这不就做完了
吗?
没有!
我们填上的最高位可是出现了很多次,但是一次都没有被记录进去。。。
这不就尴尬了?
好办,我们让剩下的$i-1$为随意选择只考虑当前最高位上出现的数就好了。
因为那些随意选择的数码已经被计入答案了,所以这么做是对的。
于是根据乘法原理,还有:
$$dp[i][j][j]+=10^{i-1}$$
之后就是数位$DP$的板子了。
注意:$slove(x)$求的是$[0,x)$满足条件的数的个数!
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 15
using namespace std;
int bit[MAXN];
long long A,B;
long long ans[MAXN][2],dp[MAXN][MAXN][MAXN];
inline long long read(){
	long long date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
long long mexp(long long a,long long b){
	long long s=1;
	while(b){
		if(b&1)s*=a;
		a*=a;
		b>>=1;
	}
	return s;
}
void solve(long long n,int d){
	int len=0;
	memset(dp,0,sizeof(dp));
	memset(bit,0,sizeof(bit));
	while(n){
		bit[++len]=n%10;
		n/=10;
	}
	for(int i=0;i<=9;i++)dp[1][i][i]=1;
	for(int i=2;i<=len;i++)
	for(int j=0;j<=9;j++){
		for(int k=0;k<=9;k++)
			for(int now=0;now<=9;now++)
				dp[i][j][now]+=dp[i-1][k][now];
		dp[i][j][j]+=mexp(10,i-1);
	}
	for(int i=1;i<len;i++)
		for(int j=1;j<=9;j++)
			for(int k=0;k<=9;k++)
				ans[k][d]+=dp[i][j][k];
	for(int i=1;i<bit[len];i++)
		for(int j=0;j<=9;j++)
			ans[j][d]+=dp[len][i][j];
	for(int i=len-1;i>=1;i--){
		for(int j=0;j<bit[i];j++)
			for(int k=0;k<=9;k++)
				ans[k][d]+=dp[i][j][k];
		for(int j=len;j>i;j--)ans[bit[j]][d]+=1LL*bit[i]*mexp(10,i-1);
	}
}
void work(){
	A=read();B=read();
	solve(B+1,0);solve(A,1);
	for(int i=0;i<=9;i++)printf("%lld ",ans[i][0]-ans[i][1]);
	printf("\n");
}
int main(){
	work();
    return 0;
}

 

 
posted @ 2018-10-09 23:15  符拉迪沃斯托克  阅读(222)  评论(0编辑  收藏  举报
Live2D