由于学长的重重推荐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));
}
}