题目:
http://acm.hdu.edu.cn/showproblem.php?pid=3555
学习下如此高端的DP;
//dp[i][j]表示计算到第i位时,状态为j的数的个数 //j=0表示之前不含49且前一位不是4,j=1表示之前不含49但前一位是4,j=2表示之前已经包含49
//dfs函数:pos为当前所处的位,have记录状态(即dp数组的第二维),doing表示前一位是否达到了其最大值,若达到则后面的一位的上限会有限制
#include<cstdio> #include<algorithm> using namespace std; __int64 dp[20][3]; int digit[20]; __int64 dfs(int pos , int have , bool doing) { if(pos == -1) return have == 2; if(!doing && dp[pos][have] !=-1) return dp[pos][have]; __int64 ans = 0; int end = doing ? digit[pos] : 9; for(int i = 0 ; i <= end; i++) { int nhave = have; if(have == 1 && i != 4) nhave = 0; if(have == 0 && i == 4) nhave = 1; if(have == 1 && i == 9) nhave = 2; ans += dfs(pos-1 , nhave , doing && i == end); } if(!doing) { dp[pos][have] = ans; } return ans; } __int64 cal(__int64 x) { int pos = 0; while(x) { digit[pos++] = x % 10; x /= 10; } return dfs(pos - 1 , 0 , 1); } int main() { memset(dp,-1,sizeof(dp)); int T; for(scanf("%d",&T) ; T-- ;) { __int64 n; scanf("%I64d",&n); printf("%I64d\n",cal(n)); } return 0; }
然后记忆化搜索
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][13][3]; int digit[10]; __int64 dfs(int pos , int pre , int have , bool doing) { if(pos == -1) return have == 2 && pre == 0; if(!doing && dp[pos][pre][have] != -1) return dp[pos][pre][have]; int ans = 0; int end = doing ? digit[pos] : 9; for(int i = 0 ; i <= end ; i ++) { int npre = (pre*10 + i) % 13; int nhave = have; if(have == 0 && i == 1) nhave = 1; else if(have == 1 && i != 1) nhave = 0; if(have == 1 && i == 3) nhave = 2; ans += dfs(pos-1 , npre , nhave , doing && i == end ); } if(!doing) dp[pos][pre][have] = ans; return ans; } int cal(int x) { int pos = 0; while(x) { digit[pos++] = x % 10; x /= 10; } return dfs(pos - 1 , 0 , 0 , 1); } int main() { memset(dp,-1,sizeof(dp)); int n; while(~scanf("%d",&n)) printf("%d\n",cal(n)); return 0; }