hdu 4722 Good Numbers(找规律,记忆化搜索,数位dp)

来源:互联网 发布:佛山顺德区网络推广 编辑:程序博客网 时间:2024/05/22 08:29

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4722

解题思路:

题目大意:

给你两个数a,b(a<=b),问你a~b满足各个数位相加能整除10的个数,含边界。

算法思想:

先枚举一下0~200内满足条件的值,0,19,28,37,46,55,64,73,82,91,109,118,127,136,145,154,163,172,181,190.规律很显然就出来了,0~10中有一个,10~20中有一个。。。可知:每十个中必有一个(自己可以在纸上画一下)。一个很大的数共有n位,前面n-1位的和是p而最后一位还没确定,最后一位可以取q=0~9,自己可以想一下结果肯定是(p+q)%10,而模上10以后的结果必是从0~9,所以每十个里面必有一个。接下来的就好办了,问你a~b满足条件的个数,就先求出边界c~d(c<=a且最大的满足条件的数,d<=b且最大的满足条件的数),最后结果就是(d-c)/10。

AC代码(找规律);

#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;bool judge(ll x){    int sum = 0;    while(x){        sum += x%10;        x /= 10;    }    if(sum % 10 == 0)        return true;    else        return false;}int main(){    int T,t = 1;    scanf("%d",&T);    while(T--){        ll a,b;        scanf("%lld%lld",&a,&b);        a--;        while(!judge(a))            a--;        while(!judge(b))            b--;        printf("Case #%d: %lld\n",t++,b/10-a/10);    }    return 0;}

AC代码(记忆化搜索):

#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int maxn = 25;ll dp[maxn][12];ll digit[maxn];ll a,b;ll dfs(int pos,int pre,bool limit){//pre表示前面各位数字之和对该数取模的结果     if(pos == -1)        return pre == 0;    if(!limit && dp[pos][pre]!=-1)        return dp[pos][pre];    ll res = 0,tmp = limit?digit[pos]:9;    for(int i = 0; i <= tmp; i++){        int new_pre = (pre+i)%10;        res += dfs(pos-1,new_pre,limit&&i==tmp);    }    if(!limit)        dp[pos][pre] = res;     return res;}ll solve(ll n){     int len=0;     while(n){         digit[len++] = n%10;         n /= 10;     }     return dfs(len-1,0,true);}int main(){     int T;     scanf("%d",&T);     for(int i = 1; i <= T; i++){         memset(dp,-1,sizeof(dp));         scanf("%lld%lld",&a,&b);         printf("Case #%d: %lld\n",i,solve(b)-solve(a-1));     }     return 0;}


dp[i][j]表示到第i位,数字和%10为j,然后进行dp,注意完全匹配的情况是要+1,而其他情况是从0 到 9 都要考虑
AC代码(数位dp):

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;ll a,b,dp[20][10];ll v[20],vn;void solve2(ll num){    vn = 0;    while(num){        v[++vn] = num % 10;        num /= 10;    }    for(int i = 1; i <= vn / 2; i++)        swap(v[i], v[vn - i + 1]);}ll solve(ll num){    if (num == -1)    return 0;    memset(dp, 0, sizeof(dp));    solve2(num);    int x = 0;    for (int i = 1; i <= vn; i++){        for (int j = 0; j < 10; j++){            for (int k = 0; k < 10; k++){                dp[i][(j + k) % 10] += dp[i - 1][j];            }        }        for (int j = 0; j < v[i]; j++) {            dp[i][(x + j) % 10]++;        }        x = (x + v[i]) % 10;    }    if (!x)        dp[vn][0]++;    return        dp[vn][0];}int main(){    int T,t = 1;    scanf("%d", &T);    while(T--){        scanf("%lld%lld",&a,&b);        printf("Case #%d: %lld\n",t++,solve(b)-solve(a-1));    }    return 0;}


0 0
原创粉丝点击