HDU - 4722 Good Numbers(数位DP)

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5969    Accepted Submission(s): 1886

题目链接:

HDU - 4722 

题目描述:

输入两个数A,B,判断从A到B之间有多少个数的各个位数上数字的和能够整除10

题解:

for(int i=le;i<=ri;i++)
        if(right(i)) ans++;

上面的方法是直接枚举,那这种方法可行不可行?

A,B的范围是1e18,那么这道题趋于时间的限制不能使用枚举法!

不过可以采用数位DP的方法去做这道题。

如果你对数位DP比较陌生的话,可以参考一下这篇博客

现在想要计算A到B中有多少个符合要求的数字,只需

solve(ri)-solve(le-1)

就行了!

很神奇吧,哈哈。

ll solve(ll x)
{
   int pos=0;//代表位数
   while(x)
   {
       a[pos++]=x%10;
       x/=10;
   }
   return dfs(pos-1,0,1);//因为是pos++,所以这里pos-1,这里已经是最高位了,这位的前面应该是0。
}

这里是solve()函数,这个函数的目的就是计算当前数之前有多少个数符合要求!

既然是数位DP,那就要说说什么是数位,就像123,1为百位,2位十位,3为个位,对每一位进行操作,然后结合dp进行优化。

那接下来有一个难点就是dfs(pos-1,0,1)了,1代表的是当前是最高位,比如说123,百位可以取0和1,如果说我现在取了1的话,这个时候dfs传入的就是1了,为什么呢?

举个例子:如果现在百位取1,那么我们的十位就只能取0/1/2,如果说现在百位取0,那么我们的十位就能取0-9里面的任意一个数,那么现在传入的1就代表我们后面要对前面位数上是不是最大数进行特判。

搜索函数如下:

#include<algorithm>
#include<cstdio>
#include<string.h>
#include<string>
#include<iostream>
using namespace std;
typedef long long ll;
int a[25];
ll dp[25][20];

ll dfs(int pos,int state,int limit)//limit判断是否达到上限
{
    if(pos==-1) return state==0;//如果pos==-1的话,就代表结束了,开始回溯
    if(!limit&&dp[pos][state]!=-1)//没有达到上限且存在
        return dp[pos][state];
    int up=limit?a[pos]:9;//计算下一位的位数
    ll ans=0;
    for(int i=0;i<=up;++i)
    {
        /*
        数位DP的模板上面这里有判断的条件,这道题可以直接用state解决。
        前面有一句if(pos==-1) return state==0;
        因为每一步进行的操作是(state+i)%10,所以只需使最后等于0就满足
        题目要求了,这样直接可以让ans++;
        */
        ans+=dfs(pos-1,(state+i)%10,limit&&i==up);
    }
    if(!limit) dp[pos][state]=ans;
    return ans;
}

ll solve(ll x)
{
   int pos=0;//代表位数
   while(x)
   {
       a[pos++]=x%10;
       x/=10;
   }
   return dfs(pos-1,0,1);//因为是pos++,所以这里pos-1,这里已经是最高位了,这位的前面应该是0。
}

int main()
{
    ll le,ri;
    int n;
    cin>>n;
    int number=0;
    memset(dp,-1,sizeof(dp));
    while(n--)
    {
        scanf("%I64d%I64d",&le,&ri);
        if(le!=0)
          printf("Case #%d: %I64d\n",++number,solve(ri)-solve(le-1));
        else
          printf("Case #%d: %I64d\n",++number,solve(ri));
    }
    return 0;
}

 

上一篇:asp.net 多个文件同时下载


下一篇:Python每日一点(001)