题意:找出区间内数中含有13的并且能被13整除的数的个数
分析:dp(i,j,k)表示i位数,余数为j;k = 0,不含13;k = 1,,不含13且末位为1;k = 2,含13
记忆化搜索,从最高位开始搜索,每次判断搜索的数是否存在上界,即当前位的值是否小于所求区间右端的数的当前位的值。
#include <bits/stdc++.h>
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;
}