數位DP
問題
求區間中滿足條件的數有多少個, ,該條件與數位有關,比如不包含數字。
思路
考慮函數表示區間中滿足條件的數的個數,那麼區間中滿足條件的數的個數爲。
然後用動態規劃的方法求。求出的每一位數字以及長度,用數組表示長度爲首位爲的滿足條件的數的個數,那麼表示長度爲的滿足條件的後綴的個數,而表示所有長度小於的滿足條件的數的個數,令。
最後求出所有長度爲的滿足條件的數的個數。對於從高位到低位,計算所有最高的位與相同且第位比小的滿足條件的數的個數,設的第位數字爲,則,如果從第位開始不滿足條件就退出循環。若本身滿足條件,則。那麼。
時間複雜度
。實際上爲的位數,而的位數可以表示爲,即,默認爲以爲底的對數。
測試
模板
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
typedef long long LL;
const int N = 20; // the maximal number of digits
LL dp[N][10]; // dp[i][j] is the amount of numbers with i digits and first digit j
int nums[N]; // the digits of n
/**
* @param n: the maximal number
* @return: the amount of numbers from 0 to n
*/
LL cal(LL n) {
int len = 0; // the length of n
// nums[i] is the i-th digit of n from right to left
while (n > 0) {
nums[++len] = n % 10;
n /= 10;
}
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= len; ++i) {
for (int j = 0; j <= 9; ++j) {
/*
update: dp[i][j]
*/
}
}
LL ans = dp[len][0]; // the numbers with length shorter than n
dp[len][0] = 0;
int pos; // the position of the digits of n
for (pos = len; pos >= 1; --pos) {
for (int j = 0; j < nums[pos]; ++j) {
/*
condition: continue
*/
ans += dp[pos][j]; // the numbers less than n
}
/*
condition: break
*/
if (dp[pos][nums[pos]] == 0) break; // no more numbers
}
if (pos == 0) ++ans; // n
return ans;
}