数位DP

由于学长的重重推荐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\n",solve(n));
    }
}

  

posted @ 2018-08-04 21:36  注册以后还能改吧  阅读(114)  评论(0编辑  收藏  举报