题目:POJ2282.
题目大意:给定一个区间
[
l
,
r
]
[l,r]
[l,r],求
[
l
,
r
]
[l,r]
[l,r]的数中
0
0
0到
9
9
9每个数的出现次数.
数据组数
T
=
5
∗
1
0
4
T=5*10^4
T=5∗104,
1
≤
l
,
r
≤
1
0
8
1\leq l,r\leq 10^8
1≤l,r≤108.
数位DP,设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示长度为 i i i开头为 j j j的数中 k k k的出现数量先跑一遍DP预处理.
然后把询问拆成 [ 1 , r ] − [ 1 , l − 1 ] [1,r]-[1,l-1] [1,r]−[1,l−1],然后枚举每一位,注意处理前导 0 0 0的情况.
时间复杂度 O ( 10 log 10 2 r + 10 T log 10 r ) O(10\log_{10}^{2}r+10T\log_{10}r) O(10log102r+10Tlog10r).
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=10;
LL l,r,pw[N+9];
void Get_pw(){
pw[0]=1;
for (int i=1;i<=N;++i) pw[i]=pw[i-1]*10;
}
LL dp[N+9][N+9][N+9];
void Get_dp(){
for (int i=0;i<N;++i) dp[1][i][i]=1;
for (int i=2;i<=N;++i)
for (int j=0;j<N;++j)
for (int k=0;k<N;++k){
for (int t=0;t<N;++t) dp[i][j][t]+=dp[i-1][k][t];
dp[i][k][k]+=pw[i-2];
}
}
LL ans[N+9];
int a[N+9],ca;
void Get_ans(LL mx,int v){
LL t=mx;
for (ca=0;mx;mx/=10) a[++ca]=mx%10;
for (int i=1;i<ca;++i)
for (int j=1;j<N;++j)
for (int k=0;k<N;++k)
ans[k]+=dp[i][j][k]*v;
for (int i=ca;i>=1;--i){
for (int j=0;j<a[i];++j){
if (!j&&i==ca) continue;
for (int k=0;k<N;++k) ans[k]+=dp[i][j][k]*v;
}
ans[a[i]]+=(t%pw[i-1]+1)*v;
}
}
Abigail start(){
Get_pw();
Get_dp();
}
Abigail work(){
for (int i=0;i<N;++i) ans[i]=0;
if (l>r) swap(l,r);
Get_ans(r,1);
Get_ans(l-1,-1);
}
Abigail outo(){
for (int i=0;i<N-1;++i)
printf("%lld ",ans[i]);
printf("%lld\n",ans[N-1]);
}
int main(){
start();
while (~scanf("%lld%lld",&l,&r)&&l+r){
work();
outo();
}
return 0;
}