数位DP 板子

来源:互联网 发布:玛丽莲曼森的衣服淘宝 编辑:程序博客网 时间:2024/05/22 18:23

//重点在于找到dp的状态, 每一维代表什么, 如何去筛选, 和前导零的影响.
贴一个常用板子: (记忆化搜索板子)

/** @Cain*/int dp[10][sta];int a[10];int dfs(int pos,int sta,bool limit)  //limit 就是为了限制当前位是否是最高位.{    if(pos == 0) return 判断条件;  //这个一般跟根据题目设的条件, 返回是否满足条件.    if(!limit && dp[pos][sta] != -1) return dp[pos][sta];//当前位不是最高位, 并且被访问过,则直接更新.    int up = limit ? a[pos] : 9;  //如果数是213,则最高位不是2时就可以枚举到9,后面更新也可以直接    //记忆化搜索, 如果是2的话, 十位只能美枚举到1而不是9, 所以有个limit.    int ans = 0;    for(int i=0;i<=up;i++){        if() 操作;        if() 操作;        .......        ans += dfs(pos-1,sta判断,limit && i == a[pos]);    }    if(!limit) dp[pos][sta] = ans;    return ans;}int cal(int x){    int pos = 1;    while(x){   //一位一位的拆开.        a[pos++] = x % 10;        x /= 10;    }    return dfs(pos-1,0,true);}void solve(){    int n,m;    //Fill(dp,-1); //这个放在外面是要根据题意来的, 若是这个数原本的性质, 则就可以放在外面.算一种优化.    while(~scanf("%d%d",&n,&m)){        Fill(dp,-1);        printf("%d\n",cal(m)-cal(n-1));    }}int main(){    int t = 1 ;    //scanf("%d",&t);    while(t--){        solve();    }}

现在举两个例子:
HDU – 2089 不要62
//数位DP入门题
AC Code

/** @Cain*/int dp[10][2];  //最大不超过10位,后面一维存前面那个数是不是6的状态.int a[10];int dfs(int pos,int sta,bool limit)  //limit 就是为了限制当前位是否是最高位.{    if(pos == 0) return 1;    if(!limit && dp[pos][sta] != -1) return dp[pos][sta];    int up = limit ? a[pos] : 9;    int ans = 0;    for(int i=0;i<=up;i++){        if(sta && i == 2) continue;  //剔除不满足条件的.        if(i == 4) continue;        ans += dfs(pos-1,i==6,limit && i == a[pos]);    }    if(!limit) dp[pos][sta] = ans;    return ans;}int cal(int x){    int pos = 1;    while(x){        a[pos++] = x % 10;        x /= 10;    }    return dfs(pos-1,0,true);}void solve(){    int n,m;    Fill(dp,-1); //62 , 4 都是这些数本身的性质,所以可以放在while外面,这算是一种优化.    while(~scanf("%d%d",&n,&m)){        if(n+m == 0) break;        printf("%d\n",cal(m)-cal(n-1));    }}int main(){    int t = 1 ;    //scanf("%d",&t);    while(t--){        solve();    }}

HDU - 3652 B-number
//这个就用三维,dp[pos][mod][sta], pos代表当前位, mod代表前面剩下的余数, sta代表前一位有1还是有13还是都没有.
AC Code

/** @Cain*/int dp[15][15][3];int a[15];int dfs(int pos,int mod,int sta,bool limit)  //limit 就是为了限制当前位是否是最高位.{    if(pos == 0) return (mod == 0 && sta == 2);  //返回满足条件的.    if(!limit && dp[pos][mod][sta] != -1) return dp[pos][mod][sta];    int up = limit ? a[pos] : 9;    int ans = 0;    int mod2,sta2;    for(int i=0;i<=up;i++){        mod2 = (mod * 10 + i) % 13;  //判断剩下的余数.        sta2 = sta;                   //判断状态.        if( sta == 1 && i == 3 ) sta2 = 2;   //这个顺序放错就GG了,还是太弱了.        else if( sta == 0 && i == 1 ) sta2 = 1;        else if( sta == 1 && i != 1 ) sta2 = 0;        ans += dfs(pos-1,mod2,sta2,limit && i == a[pos]);    }    if(!limit) dp[pos][mod][sta] = ans;    return ans;}int cal(int x){    int pos = 1;    while(x){        a[pos++] = x % 10;        x /= 10;    }    return dfs(pos-1,0,0,true);}void solve(){    int n;    Fill(dp,-1);    while(~scanf("%d",&n)){        printf("%d\n",cal(n)-cal(0));    }}int main(){    int t = 1 ;    //scanf("%d",&t);    while(t--){        solve();    }}
原创粉丝点击