This way

题意:

定义S(x)=十进制下x所有位的和。问你有多少对A,B使得S(A)>S(B)&&A<=B

题解:

我一开始题目看错了,没注意到A和B的大小关系,所以一开始的数位DP就写错了,看对题目之后我往生成树那方面去想,想找子树大小什么的关系,但是最后找不出来…赛后看了别人的代码,真的太强了,或许这才是记忆化搜索吧…
dp[i][j][k][l]表示到了第i个位置,当前数的和为j,k表示较大数是否到达上界,l表示较小数是否到达上界。
后面这两维真的精髓,这样就可以将较大的数和较小的数区分开来。然后每次枚举的时候,i表示较大数,j表示较小数,sum+j-i表示他们的差加了多少。最后如果sum>N的话,就表示较小数的位上的和大于较大数。
tql/QAQ.jpg

#include<bits/stdc++.h>
using namespace std;
const int N=905,M=105;
#define ll long long
const ll mod=1e9+7;
ll dp[M][N*2][2][2];
char s[N];
int n;
ll dfs(int pos,int sum,int m1,int m2){
    if(pos>n)
        return sum>N;
    if(~dp[pos][sum][m1][m2])
        return dp[pos][sum][m1][m2];
    ll ans=0;
    int top=m1?s[pos]-'0':9;
    for(int i=0;i<=top;i++){
        int t2=m2?i:9;
        for(int j=0;j<=t2;j++)
            ans=(ans+dfs(pos+1,sum+j-i,m1&&i==top,m2&&j==t2))%mod;
    }
    dp[pos][sum][m1][m2]=ans;
    return ans;
}
int main()
{
    memset(dp,-1,sizeof(dp));
    scanf("%s",s+1);
    n=strlen(s+1);
    printf("%lld\n",dfs(1,N,1,1));
    return 0;
}

本文地址:https://blog.csdn.net/tianyizhicheng/article/details/107617565