【背景】
採用記憶化搜索實現。
搜索:dfs(i,j,k,ismax)
完整代碼:
/*15ms,232KB*/
#include<cstdio>
#include<cstring>
const int mx = 10;
int bit[mx], dp[mx][2];
///複雜度O(log n)
///若ismax爲true則後面循環的時候i只能取0~bit[len]
///is6記錄上一位是否爲6
int dfs(int len, bool is6, bool ismax)
{
if (len == 0) return 1; ///能遞歸到這裏說明這串數符合要求,返回1
if (!ismax && dp[len][is6] >= 0) return dp[len][is6];
///若ismax爲true,則還需要繼續向下遞歸
///爲什麼?對於n=5321來說,遞歸中的2xxx和3xxx可以直接在len=3時返回(因爲xxx這顆子樹已經被前面的1xxx算出來了)
///但是在算5xxx時並不能直接返回,因爲後面的xxx至多能取到321,還需要進一步往下遞歸
int cnt = 0, maxnum = (ismax ? bit[len] : 9);
for (int i = 0; i <= maxnum; ++i)
{
if (i == 4 || is6 && i == 2) continue; ///不能有4,或者前一位爲6且該位爲2
cnt += dfs(len - 1, i == 6, ismax && i == maxnum); ///ismax && i == maxnum 用來判斷是否達到位值上限
}
return ismax ? cnt : dp[len][is6] = cnt; ///根據ismax來決定是否記錄dp(比如dp[3][1]記錄的是6xx的所有數,即從600到699中的符合條件的數的個數)
}
int f(int n)
{
int len = 0;
while (n)
{
bit[++len] = n % 10;
n /= 10;
}
return dfs(len, false, true); ///從首位開始遞歸統計
}
int main()
{
int a, b;
memset(dp, -1, sizeof(dp));
while (scanf("%d%d", &a, &b), a)
printf("%d\n", f(b) - f(a - 1));
return 0;
}
轉載請註明:http://blog.csdn.net/synapse7/article/details/21006265