LightOJ-1140(数位DP)

题意:求n~m之间数字里共有多少个0

/**

**/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 30;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
//长度为i的数字有j个0
ll dp[maxn][maxn];
ll dig[maxn];
//fp是limit标记,flag判断是否一直是0
ll dfs(int len, ll pre, int flag,bool fp)
{
    if(len == 0)
    {
        if(flag)
            return 1;
        return pre;
    }
    //记忆化搜索
    if(!fp && dp[len][pre]!=-1 && !flag)
        return dp[len][pre];
    int fpmax = 9;
    if(fp)
        fpmax = dig[len];
    ll ret = 0;
    for(int i = 0; i<=fpmax; i++)
    {
        ll tmp;
        if(flag)
            tmp = dfs(len-1,pre,flag&&(i==0),fp&&(i==fpmax));
        else
        {
            if(i == 0)
                tmp = dfs(len-1,pre+1,flag,fp&&(i==fpmax));
            else
                tmp = dfs(len-1,pre,flag,fp&&(i==fpmax));
        }
        ret += tmp;
    }
    if(!fp && !flag)
        dp[len][pre] = ret;
    return ret;
}

int solve(ll x)
{
    if(x == -1)
        return 0;
    int len = 0;
    while(x)
    {
        dig[++len] = x%10;
        x /= 10;
    }
    ll ans = dfs(len,0,1,true);
    return ans;
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    int tt = 1;
    while(T--)
    {
        memset(dp,-1,sizeof dp);
        ll n,m;
        scanf("%lld%lld",&m,&n);
        int ans = solve(n)-solve(m-1);
        printf("Case %d: %lld\n",tt++,ans);

    }


    return 0;
}

 

你可能感兴趣的:(算法学习,动态规划)