數字dp
目前見的比較少,最為經典的莫過於不要62,或許以前都是暴力求解。例如求解1~n
中,數字x
出現的次數這類題,暴力列舉每個數的時間複雜度為 o(n
)o(n)
o(n)
,再列舉每一位的時間複雜度為 log
10nlog_^n
log10n
,數字一大妥妥超時。
值得一提的是,2020 的藍橋杯,第一道簽到題就是暴力做法…
338. 計數問題
重點:數字dp
、分情況討論
問題分析及抽象:
該問題實際上是需要求解從1~n
中0,1,2,...,9
分別出現的次數。那麼可實現乙個count(n, x)
函式,該函式可求出從1~n
中所有數,數字x
出現的次數。那麼求解區間[a,b]
的x
出現的次數就可將問題轉化為count(b, x) - count(a - 1, x)
。就是乙個簡單的字首和思想。
例如:求解1~n
中x = 1
出現的次數,數字n
的每一位以abcdefg
代替,7 位數。
注意:以上分析只適用於1~9
這些數字的數字個數。關於數字 0 的前導 0 問題,再下面的邊界情況著重討論。
邊界情況:
時間複雜度是很低的,假設是個 8 位數字:
這個題目其實不太經典…為什麼將其歸結為dp
問題?這樣理解dp
本質上就是用某個具體的數,比如f[i]
,表示某乙個集合,這裡也是用某個數來表示某乙個集合,所以這裡將這道題歸到了dp
這一類。
並且這個題目的分情況討論也是值得學習的。
往後的數字dp
題目會正經一點…
**:
// 例子 1~123456 求3出現的次數
// 第一位:最高位:3***xx 是不存在這種情況的,故貢獻個數為 0
// 第二位:其實統計的是0~3~9999的情況,10000,0~3~9999 總共10000
// 第三位:統計的是00-11~3~000-999的情況,總共12*1000 = 12000,當前位是3,等於3,還需要123000~123456,456+1種情況
// 第四位:統計的是000-123-3-00~99的情況,總共123*100 = 12300,當前位是4,大於3,還需要123(4)300~123399,100種情況
// 第五位:統計的是0000-1234-3-9的情況,總共1234*10=12340,當前位是5,大於3,還需要1234(5)30~123439,10種情況
// 第六位:統計的是00000-12345-3的情況,總共12345,當前位是6,大於3,還需要123453~123433,1種情況
// 總的情況就是;10000+12000+12300+12340+12345+(456+1)+100+10+1=59553
/*#include using namespace std;
int main()
}cout << res << endl; // 暴力輸出59553,藍橋杯簽到題搞定hh
return 0;}*/
#include
#include
using
namespace std;
intget
(vector<
int> num,
int l,
int r)
intpower10
(int x)
intcount
(int n,
int x)
n = num.
size()
;int res =0;
for(
int i = n -1-
!x; i >=0;
--i)
if(num[i]
== x) res +
=get
(num, i -1,
0)+1
;// 當前位與列舉的x相等
else
if(num[i]
> x) res +
=power10
(i);
}return res;
}int
main()
return0;
}
計數問題(數字dp)
給定兩個整數 a 和 b,求 a 和 b 之間的所有數字中0 9的出現次數。例如,a 1024,b 1032,則 a 和 b 之間共有9個數如下 1024 1025 1026 1027 1028 1029 1030 1031 1032 其中 0 出現10次,1 出現10次,2 出現7次,3 出現3次...
數字DP 計數問題
題目鏈結 第一次做真的很難,總之十分耗費時間。include include include using namespace std const int n 10 get前面字首部分的數值,即前面字首總方案數 intget vector int num,int l,int r 字尾有幾位就是十的幾次...
演算法題 數字dp 計數問題(Python
給定兩個整數 a 和 b,求 a 和 b 之間的所有數字中0 9的出現次數。例如,a 1024,b 1032,則 a 和 b 之間共有9個數如下 1024 1025 1026 1027 1028 1029 1030 1031 1032 其中 0 出現10次,1 出現10次,2 出現7次,3 出現3次...