数位dp详解及模板

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

对于此类问题,我们一般设dpdp数组dp[i][j]dp[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整除的满足条件的数的个数了
而对于任意数xx,只需要将其拆成x=x1100+x2101+x3102+......x=x1∗100+x2∗101+x3∗102+......的形式即可
然后求出xxyy的个数,相减便是答案

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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; jif(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 <1)-ask(m)<return 0;

}

转载于:https://www.cnblogs.com/bestsort/p/10588853.html

你可能感兴趣的:(数位dp详解及模板)