数位DP递归版的基本模式。
数位DP经常询问的是在某个区间内符合某种条件的个数。
我个人喜欢用递归,因为简单好些。
先给个基本模式。
hdu 2089 不要62
http://acm.hdu.edu.cn/showproblem.php?pid=2089
询问区间中不包含4和62的个数。
#include<cstring> #include<cstdio> #include<iostream> #define FOR(i,a,b) for(int i=a;i<=b;++i) #define clr(f,z) memset(f,z,sizeof(f)) using namespace std; const int mm=11; int dp[mm][mm][2];///位数,last num,has contain bad num int bit[mm]; int DP(int pp,int last,bool has,bool big) { if(pp==-1)return has==0;///no contain bad num if(big&&dp[pp][last][has]!=-1)return dp[pp][last][has]; int ret=0; int kn=big?9:bit[pp]; FOR(i,0,kn) { ret+=DP(pp-1,i,has||(i==4||(last==6&&i==2)),big||kn!=i); } if(big)dp[pp][last][has]=ret; return ret; } int get(int x) { int pos=-1; while(x) { bit[++pos]=x%10;x/=10; } return DP(pos,0,0,0); } int main() { clr(dp,-1); int n,m; while(cin>>n>>m) { if(n==0&&m==0)break; cout<<get(m)-get(n-1)<<endl; } }
其中状态有个注意点,就是设计的DP 状态能不能适用于所有的分组数据,如果可以就只需要初始化一次,如果不行,那每次执行都需要初始化。
比如:
如果设计状态是dp[bit][statue] 表示i位长,能达到值为statue 的最优值,那就得每次初始化,那就T 了,因为每次询问所要求小于的数都不一样。
但如果换一个表式就可以了,表示bit位长,比statue小的有多少个,那就满足所有的询问了,就只需要初始化一次。
具体看这
http://blog.csdn.net/nealgavin/article/details/11703049
/***********************************************************************************************/
然后:数位DP 最重要的就赛状态设计和,一些状态精简之类的问题了。
《1.》 像这一题就是和LCM有关的数位DP 。
CodeForces 55D Beautiful numbers (数位DP+状态简化,5级)
http://blog.csdn.net/nealgavin/article/details/10446739
很容易能想到三维DP dp[第几位][模上最小公倍数数的余数][最小公倍数]
最小公倍数到2520 为止 ,故 需要 19x2520x2520 爆空间了。
但实际上能取到的最小公倍数没有2520个,只要几十个,因此可以哈希一下,因为DP只要记录其不同状态就可以了。
dp不需要每个数都算原因是不同数的mod数不同。因此不会错
接下来,就是水数位DP了。
《2.》SPOJ 10606. Balanced Numbers (数位DP,4级)
http://blog.csdn.net/nealgavin/article/details/10335221
《3.》这道是好题。状态压缩的递增自序列数位DP ,如果都理解透的化也是可以秒的。
《4.》这到题就需要理解数位DP,它到底在求的是什么。
hdu 3709 Balanced Number(数位DP,5级)
http://blog.csdn.net/nealgavin/article/details/10084467
《5.》好题,需要设计多种状态,要分清楚。