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 long
int 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(' ');
    }
}
原文地址:https://www.cnblogs.com/SiriusRen/p/6654378.html