数位dp小技巧

一个奇怪的东西

正反都能dp!:
正常我们数位dp都是从高到低,以这样的方式保证其小于给定数->

ll n;
int num[N],l;
ll dp[];
ll dfs(int p,int lim){
    if(p==0) return 1;
    if(!lim&&~dp[]) return dp[];
    int Uplim=lim?num[p]:9;
    ll res=0;
    for(int i=0;i<=Uplim;i++) {
        res+=dfs(p-1,lim&&(i==Uplim));
    }
    if(!lim) dp[]=res;
    return res;
}

int main(){
    scanf("%lld",&n);
    while(n) num[++l]=n%10,n/=10;
    printf("%lld\n",dfs(l,1));
}

然而从低到高位应该是这样的:

ll n;
int num[N],l;
ll dp[];
ll dfs(int p,int fl){
    if(p==l+1) return fl;
    if(~dp[]) return dp[];
    ll res=0;
    for(int i=0;i<10;i++) {
        res+=dfs(p+1,i<num[p]||(i==num[p]&&fl));
    }
    return dp[]=res;
}

int main(){
    scanf("%lld",&n);
    while(n) num[++l]=n%10,n/=10;
    printf("%lld\n",dfs(1,1));
}

这个在某些特殊情况下可以消除一些后效性和麻烦的步骤

注意每次跑不同数的时候要清空dp

原文地址:https://www.cnblogs.com/chasedeath/p/11269342.html