【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)
1833: [ZJOI2010]count 数字计数
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 2774 Solved: 1230
[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
HINT
30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。
Source
【题解】【数位dp】
[自己乱搞的结果就是写了三遍。。。每一遍想法都有所改变……蠢哭]
【刚开始想的是用f[i][j][k][o][x][y]表示第i位放j时k的出现次数,o表示前导0,x,y表示是否到达左右边界,每次下一位与当前位的相同时,更新时就加1,然后,怎么搞都错成一团。。。扔掉!】
【然后,又考虑用f[i][j][k][o][x][y]表示第i位放j时j出现的次数k,o表示前导0,x,y表示是否到达左右边界,每一次都是加上更新过来的f[i][j][k][o][x][y],然后,发现怎么搞1都不对。。。又扔掉!】
【最后,结合前两次的经验,先循环一重当前要求数t的出现次数,用f[i][j][k][o][x][y]表示第i位放j时t的出现次数k,o表示前导0,x,y表示是否到达左右边界。循环9次,卡过了。。。】
【注意,这种方法,由于要判断前导0,把零先去掉了,如果区间中包含0的话,要特判】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll a,b,ans;
int al[15],ar[15],left[15],right[15],l,r,len;
int f[15][12][15][3][3][3];
int main()
{
freopen("int.txt","r",stdin);
freopen("my.txt","w",stdout);
int i,j,k,xx;
scanf("%lld%lld",&a,&b); xx=a;
while(a) left[++l]=a%10,a/=10;
while(b) right[++r]=b%10,b/=10;
len=max(l,r);
memset(f,0,sizeof(f));
for(i=1;i<=len;++i) al[len-i+1]=left[i],ar[len-i+1]=right[i];
for(int t=0;t<=9;++t)
{
memset(f,0,sizeof(f));
for(i=al[1];i<=ar[1];++i) f[1][i][i==t&&i!=0][i==0][i==al[1]][i==ar[1]]=1;
for(i=1;i<len;++i)
for(j=0;j<=9;++j)
for(k=0;k<=12;++k)
for(int o=0;o<=1;++o)
for(int x=0;x<=1;++x)
for(int y=0;y<=1;++y)
if(f[i][j][k][o][x][y])
{
if(x&&y)
{
for(int h=al[i+1];h<=ar[i+1];++h)
{
int p;
if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
else p=0,f[i+1][h][0][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
}
continue;
}
if(!x&&!y)
{
for(int h=0;h<=9;++h)
{
int p;
if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
}
continue;
}
if(!x)
{
for(int h=0;h<=ar[i+1];++h)
{
int p;
if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
}
continue;
}
if(!y)
{
for(int h=al[i+1];h<=9;++h)
{
int p;
if(h||!o) p=k+(t==h),f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
else p=0,f[i+1][h][p][o&(h==0)][x&(h==al[i+1])][y&(h==ar[i+1])]+=f[i][j][k][o][x][y];
}
continue;
}
}
ans=0;
for(i=0;i<=9;++i)
for(j=1;j<=12;++j)
for(k=0;k<=1;++k)
ans+=(ll)(f[len][i][j][k][1][1]+f[len][i][j][k][1][0]+f[len][i][j][k][0][1]+f[len][i][j][k][0][0])*j;
if(!t&&!xx) printf("%lld ",ans+1);
else printf("%lld ",ans);
if(t==9) printf("\n");
}
return 0;
}
既然无能更改,又何必枉自寻烦忧