您的位置:首页 > 其它

BZOJ 1799 浅谈数位动态规划再进阶

2017-09-22 08:59 316 查看


世界真的很大

感觉对于数位动态规划的计数问题还是有点眉目了

起码基本上模板的感觉是有了

剩下的就是状态设计的问题,设计怎么样的状态可以让搜索时得以保存?

开始研究。。

看题先:

description:

给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。


input:

10 19


output:

3


一看到这道题就直接想dfs

由于自己被什么什么整除,肯定DFS的时候要保存一个每一位的mod数,然后又要数位和,那就保存一个数位和

然后DFs很快就出来了

dnt dfs(int pos,int sum,int val,int lim)


sum代表数位和,val代表mod数

但忽然发现mod的数是数位和,不唯一,没法每次保存,而且在数位和本身算出来之前,没法mod

那就改变状态,val代表这个数是什么,在最后一位的时候判断能不能整除

那么这时大暴力搜索已经可以写出来了,现在再套上一个记忆化的DP数组就是数位DP了

考虑设计DP的状态,这个一般是根据dfs的参数来的,f(i,j,k)

表示数位为i,前几位和为j,val为k的答案

好像不大对。。

val保存的是前几位的状态的答案,也就是说,两次DFSval相同,当前仅当DFS枚举的前几位全部相同才行

而DFS每个数只会枚举一次。。这和暴力没什么区别。。

考虑为什么数位DP能够优化,是因为他提前记录了现在需要继续转移的“后继”状态,相当于是后几位的答案,在多次访问后继状态时实行时间的优化

但是val恰恰是指前几位的数是什么。。跟后继不沾边儿

考虑为什么val必须要保存前几位的数是什么,因为不同的数的mod数不同,没法单单记录一个整除的余数来转移,也就是说,问题出在不同的数的数位和不同,导致mod的数不同,没法记录一个公共状态

怎么办呢

每个数的mod数不同,就没法保持当前状态的“后继”状态的答案,这的却是个问题

但是反过来说,如果mod数确定,不就可以保存后继状态了吗?

看一下题目,这个mod的数究竟是什么,原来是数位和

10^18的范围,就是说有18位数位,考虑每一位最大都是9,数位和最多不过 【162】

嗯~

好像思路显而易见了

我们考虑去枚举这样的数位和,不过枚举162次而已

问题就转化成了,数位和为i,且被i整除的数有多少

而这样一来,每次DFS时mod数相同,就可以递归mod的余数了,而一个余数加上后继的sum,表示的就是一堆后继的状态

和之前的f数组只会访问一次不同,这个可是多次访问的,记忆化成功

完整代码:

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long dnt;

dnt f[20][170][170];
int a[20];

dnt dfs(int pos,int sum,int val,int mod,int lim)
{
dnt ans=0;
if(pos==-1) return sum==0&&val==0;
if((pos+1)*9<sum) return 0; // 剪枝而已无须在意
if(!lim && f[pos][sum][val]!=-1) return f[pos][sum][val];
int up= lim ? a[pos] : 9;
for(int i=0;i<=up;i++)
{
if(sum<i) break ;
ans+=dfs(pos-1,sum-i,(val*10+i)%mod,mod,lim && i==up);
}
if(!lim) f[pos][sum][val]=ans;
return ans;
}

dnt solve(dnt n)
{
int cnt=0;
dnt ans=0;
memset(a,0,sizeof(a));
while(n)
{
a[cnt++]=n%10;
n/=10;
}
for(int i=1;i<=9*cnt;i++)
{
memset(f,-1,sizeof(f));
ans+=dfs(cnt-1,i,0,i,1);
}
return ans;
}

int main()
{
dnt a,b;
cin >> a >> b;
cout << solve(b)-solve(a-1) << endl;
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/


嗯,就是这样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: