[BZOJ1833][ZJOI2010]count 数字计数(数位dp)

来源:互联网 发布:电脑在线看电视软件 编辑:程序博客网 时间:2024/04/30 01:17

题目描述

传送门

题解

首先枚举要计算个数的数字x
f(i,j,k,0/1,0/1,0/1)表示前i位,第i位填数字j,是x的数字有k个,是否卡下界L,是否卡上界R,1~i位是否都是前导0的数字个数。
那么答案即为f(n,j,k,0/1,0/1,0)*k
注意转移的时候要分别处理是前导0和不是前导0的情况。

代码

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define LL long longint n;int a[20],b[20];LL L,R,f[20][20][20][2][2][2],ans;int main(){    scanf("%lld%lld",&L,&R);    while (L)    {        a[++a[0]]=L%10;        L/=10;    }    while (R)    {        b[++b[0]]=R%10;        R/=10;    }    n=max(a[0],b[0]);    for (int i=1;i<=n/2;++i) swap(a[i],a[n-i+1]);    for (int i=1;i<=n/2;++i) swap(b[i],b[n-i+1]);    for (int x=0;x<=9;++x)    {        memset(f,0,sizeof(f));        for (int i=a[1];i<=b[1];++i) f[1][i][i==x&&x!=0?1:0][i==a[1]?1:0][i==b[1]?1:0][i==0?1:0]=1;        for (int i=1;i<n;++i)            for (int j=0;j<=9;++j)                for (int k=0;k<=n;++k)                    for (int c=0;c<=1;++c)                        for (int d=0;d<=1;++d)                            for (int e=0;e<=1;++e)                            {                                int l,r;                                if (c&&d) l=a[i+1],r=b[i+1];                                else if (!c&&!d) l=0,r=9;                                else if (!c) l=0,r=b[i+1];                                else if (!d) l=a[i+1],r=9;                                for (int t=l;t<=r;++t)                                {                                    if (!e)                                    f[i+1][t][t==x?k+1:k][c&(t==a[i+1]?1:0)][d&(t==b[i+1]?1:0)][0]+=                                    f[i][j][k][c][d][e];                                    else                                    f[i+1][t][t==0?0:(t==x?1:0)][c&(t==a[i+1]?1:0)][d&(t==b[i+1]?1:0)][e&(t==0)?1:0]+=                                    f[i][j][k][c][d][e];                                }                            }        ans=0;        for (int j=0;j<=9;++j)            for (int k=1;k<=n;++k)                for (int c=0;c<=1;++c)                    for (int d=0;d<=1;++d)                        ans+=f[n][j][k][c][d][0]*(LL)k;        printf("%lld%c",ans," \n"[x==9]);    }}

总结

①写这个要细心。每一个状态一定要表示得精确。

0 0
原创粉丝点击