首页 > 代码库 > BZOJ 1833 数位DP

BZOJ 1833 数位DP

思路:

数位DP

f[i][j][k]表示走到第i位 开头位j 数字k 出现的次数

$f[i][j][k]+=f[i-1][l][k];$
$f[i][j][j]+=base[i]$

calc的时候要有特殊的技巧...(我看题解学会的

//By SiriusRen#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define int long longint l,r,f[15][10][10],base[15],ans[10];void calc(int m,int fl){    if(!m)return;    int p=1,len=0;    for(;10*p<=m;len++,p*=10);    for(int i=1;i<=len;i++)        for(int j=1;j<=9;j++)            for(int k=0;k<=9;k++)                ans[k]+=fl*f[i][j][k];    for(int j=1;j<m/p;j++)        for(int k=0;k<=9;k++)            ans[k]+=fl*f[len+1][j][k];    ans[m/p]+=fl*(m%p+1),m%=p,p/=10;    for(int i=len;i;i--){        for(int j=0;j<m/p;j++)            for(int k=0;k<=9;k++)                ans[k]+=fl*f[i][j][k];        ans[m/p]+=fl*(m%p+1),m%=p,p/=10;    }}signed main(){    scanf("%lld%lld",&l,&r),base[1]=1;    for(int i=2;i<=13;i++)base[i]=base[i-1]*10;    for(int i=1;i<=13;i++)        for(int j=0;j<=9;j++){            for(int k=0;k<=9;k++)                for(int l=0;l<=9;l++)                    f[i][j][k]+=f[i-1][l][k];            f[i][j][j]+=base[i];        }    calc(l-1,-1),calc(r,1);    for(int i=0;i<=9;i++){        printf("%lld",ans[i]);        if(i!=9)putchar( );    }}

 

BZOJ 1833 数位DP