HDU 4507 吉哥系列故事——恨7不成妻 数位DP--思路分析

本篇博客只涉及我对这个题目的理解和公式方式的推导,没有完整的代码, 本篇一共三个方法分析,第一个是略写,后两个是重点,想看正解思路直接跳第三个方法就好
题目要求出L,R之间与7无关的数字的平方和,而且范围在1e18之间,很容易想到是数位DP。这种时候就出现了不同的思路。
第一种是直接往爆搜靠拢,pos=0时,说明数据合理,return 这个数字的平方值。这个方法在我看来肯定不行,就算结果算对了,每一个符合条件的数字也至少会计算一次平方值,感觉会T,话说,这就是爆搜+记忆化了啊。

第二种是稍好一点,数位DP的思路已经理解了,不是最后计算平方值,而是一边往下搜索,一边维护当前平方值,每次加一位数字之后,就维护新的平方值,同时保证不同数字的后续状态能重合,这样就能在搜索到不同的数字时,直接return,而不是再搜索一次,有效的节约时间。

我们来分析一下(我的WA做法)这种做法的过程,也便于理解最后的正解。
对于(a+b+c)^2,我们可以写成
a * a
b * a + b * a + b * b
c * a + c * a + c * b +c * b + c * c
注意到了么,每个数字乘以的数字都是都是不超过自己的,对于每次增加的一个新数字,我们的新平方和sqsum=原sqsum + c * c +c * sum(数字a+b之和)
我们把这个结论应用在数位DP维护平方和过程中,那么就可以一边增加新的数字,一边维护平方和。只要把公式变成(a * 100 + b * 10 +c)^2 这样就可以很好契合,加入d之后就变成 (a * 1000 + b * 100 +c * 10 +d) ^ 2 = (a * 100+b * 10+c)^2 * 100 + d * (a * 1000 + b * 100 +c * 10) * 2 + d * d
我们用s_sum维护前缀和,当插入c 时,s_sum=a * 10+b
插入c之后,s_sum=a * 100+b*10+c
这样就能通过s_sum来一直维护平方和
然后用sum维护数位和%7, sta维护搜索的数字%7,这样就能在最后直接判断这个数字是不是0来判断是不是7的倍数。
同时,dp数组就会变成不超过[ len ][ 7 ][ 7 ]的大小,相对于1e18个数字,这个范围很小,也就是非常多的数据都会重合,减少了非常多的重复搜索。
下面的写法也能通过样例,似乎这就是正解。

//pos位置 sum数位之和 sta余数 limit是否达到上限 cal记录当前平方值  s_sum记录当前数字是多少
LL dfs(int pos,int sum,int sta,bool limit, LL cal,LL s_sum)
{
   
    if(pos==0) {
   
        if(sum==0||sta==0)
            return 0;
        return cal;
     }
    if(!limit&&dp[pos][sum][sta]!=-1) return dp[pos][sum][sta];
    int up=limit?a[pos]:9;
    LL res
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值