HDU 3652

题意:找出区间内数中含有13的并且能被13整除的数的个数

分析:dp(i,j,k)表示i位数,余数为j;k = 0,不含13;k = 1,,不含13且末位为1;k = 2,含13

            记忆化搜索,从最高位开始搜索,每次判断搜索的数是否存在上界,即当前位的值是否小于所求区间右端的数的当前位的值。

#include 

using namespace std;
typedef long long ll;
ll dp[15][13][3];        //dp(i,j,k)表示i位数,余数为j;k = 0,不含13;k = 1,,不含13且末位为1;k = 2,含13
int dig[15];
ll n;
int cnt;

void init(){
    memset(dp,-1,sizeof(dp));
    ll tmp = n;
    cnt = 0;
    while(tmp){
        dig[++cnt] = tmp%10;
        tmp /= 10;
    }
}

ll dfs(int pos,int pre,int mod,int limit,int flag){    //当前位置,前一个数,余数,是否有上界,是否有13
    ll ans = 0;
    if(pos == 0)
        return flag && (mod == 0);
    if(!limit && flag && dp[pos][mod][0] != -1)
        return dp[pos][mod][0];
    if(!limit && !flag && pre == 1 && dp[pos][mod][1] != -1)
        return dp[pos][mod][1];
    if(!limit && !flag && pre != 1 && dp[pos][mod][2] != -1)
        return dp[pos][mod][2];
    int End = limit?dig[pos]:9;           //无上界就直接设为9,否则为当前位数的值
    for(int i = 0;i <= End;i++){
        ans += dfs(pos-1,i,(mod*10+i)%13,limit && (i == End),flag || (pre == 1 && i == 3));
    }
    if(!limit){
        if(flag)
            dp[pos][mod][0] = ans;
        if(!flag && pre == 1)
            dp[pos][mod][1] = ans;
        if(!flag && pre != 1)
            dp[pos][mod][2] = ans;

    }
    return ans;

}
int main(){
    while(scanf("%lld",&n) != EOF){
        init();
        printf("%lld\n",dfs(cnt,0,0,1,0));
    }
    return 0;
}


你可能感兴趣的:(数位dp)