习题:数字计数(数位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;
}