数位dp详解及模板

数位dp一般应用于:
求出在给定区间 [ A , B ] 内,符合条件 P ( i ) 的数 i 的个数.条件 P ( i ) 一般与数的大小无关,而与 数的组成有关.
比如说在HDU2089中, 让求区间内数中不有462的数字个数之和

对于此类问题,我们一般设 d p 数组 d p [ i ] [ j ] ,表示i位数,最高位是j的数,不含有624的数有多少个
对于上述不含有624的要求,递推式如下

这里写图片描述
换成代码就是:

if(j==4)
    dp[i][j] = 0;
else{
    for(int k=0;j<=9;k++){
        if(j==6&&k==2)
            continue;
        dp[i][j] += dp[i-1][k];
    }
}

到此,我们就能求对于所有能被10整除的满足条件的数的个数了
而对于任意数 x ,只需要将其拆成 x = x 1 10 0 + x 2 10 1 + x 3 10 2 + . . . . . . 的形式即可
然后求出 x y 的个数,相减便是答案

#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define IN freopen("in.txt","r",stdin)
#define OUT freopen("out.txt","w",stdout)
#define IO do{\
    ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);}while(0)
using namespace std;
typedef long long ll;
const int maxn =  1e4+10;
const int MAXN = 1e6+10;
const int INF = 0x3f3f3f3f;
const int inf = 0x3f;
const double EPS = 1e-7;
const double Pi = acos(-1);
const int MOD = 1e9+7;
int dp[15][15];
int num[15];
void init()
{
    dp[0][0] = 1;
    for(int i=1; i<=9; i++)
        for(int j=0; j<=9; j++)
        {
            if(j==4)
                dp[i][j] = 0;
            else
                for(int k=0; k<=9; k++)
                {
                    if(j==6&&k==2)
                        continue;
                    dp[i][j] += dp[i-1][k];
                }
        }
}
int ask(int x)
{
    ll ans = 0;
    int cnt = 0;
    while(x)
        num[++cnt] = x%10,x/=10;
    num[cnt+1] = 0;
    for(int i=cnt; i>=1; i--)
    {
        for(int j=0; j<num[i]; j++)
        {
            if(j==4||(j==2&&num[i+1]==6))
                continue;
            ans += dp[i][j];
        }
        if(num[i] == 4||(num[i]==2&&num[i+1]==6))
            break;
    }
    return ans;
}
int main()
{
    IO;
    //IN;
    int n,m;
    init();
    while(cin >> m >>n &&(n||m))
        cout <<ask(n+1)-ask(m)<<endl;
    return 0;

}

猜你喜欢

转载自blog.csdn.net/bestsort/article/details/81382121