由于学长的重重推荐DP很重要,最近一直刷DP
刷到数位DP发现自己确实很不擅长这方面
因此打算做一些总结:
1.每次都是求前N个数,对于L~R的可以求前R减去前L
2.对于前N个,可以先把每一位放到数组,跑一次dfs(f[x]代表,n的第x位
3.对于dfs时候,分为两种:(1)是之前每一位都是与N的数相同(当前位所选的数不能超过f[x],只能遍历0~f[x]) 只需要增设一个标记zt=1
(2)是之前有过一位x所选的值低于f[x],那么现在无论如何选都不用怕超过N了,可以遍历0~9了 zt=0
4.对于dfs时,可以标记很多值,例如(1)求不能含有62的数,这时可以标记前一位是否是6
(2)求不能含有所有位之和能被7整除的,这时可以标记之前所有位%7的值
5.对于dfs时,可以用数组记录一下,但是记录时只能记录zt==0时的值,需要初始化为-1,只有不为-1时才能直接输出(这里老忘写!=-1
感觉一般都是一个 solve函数(处理出每一位)+dfs
举个例子:hdu3652 (kuangbin专题真的好方便
#include<stdio.h> #include<string.h> #define rep(i,j,k) for(long long i=j;i<=k;++i) long long dp[25][15][3][3]; long long ff[24]; long long f[25]; long long dfs(long long x,long long sum,long long zt,long long is13,long long is1) { if(x==-1) return sum==0&&is13; if(!zt&&dp[x][(13-sum)%13][is13][is1]!=-1) return dp[x][(13-sum)%13][is13][is1]; long long ans=0; if(zt) { ans=dfs(x-1,(sum+ff[x]*f[x])%13,1,is13||(is1&&f[x]==3),f[x]==1); rep(i,0,f[x]-1) ans=ans+dfs(x-1,(sum+ff[x]*i)%13,0,is13||(is1&&i==3),i==1); } else { rep(i,0,9) ans=ans+dfs(x-1,(sum+ff[x]*i)%13,0,is13||(is1&&i==3),i==1); dp[x][(13-sum)%13][is13][is1]=ans; } return ans; } long long solve(long long x) { long long len=0; while(x) { f[len++]=x%10; x=x/10; } return dfs(len-1,0,1,0,0); } int main() { ff[0]=1; rep(i,1,20) ff[i]=ff[i-1]*10; long long n; memset(dp,-1,sizeof(dp)); while(scanf("%lld",&n)!=EOF) { printf("%lld ",solve(n)); } }