我leo_jose終於會用markdown寫部落格了
數字dp是一種計數用的dp,用來統計乙個區間[left, right]內滿足某些條件的數的個數。所謂數字dp,字面意思就是在數字上進行dp
實質就是優雅一點的暴力列舉,使其滿足dp的性質,然後記憶化
對於乙個求區間中滿足條件數的個數,最簡單暴力如下:
for
(int i=left;i<=right;i++)if
(zhe_ge_shu_man_zu_tiao_jian_le_ma
(i))
ans++
;//這樣列舉要是能過就不會出現數字dp這個東西了
數字dp:從最高位往下,例如:right=2019
那麼我們從千位開始列舉:0,1,2
然後,每一位列舉懂不能讓列舉的這個數超過2019的上界,當千位列舉了1,那麼百位就是0~9,因為千位1已經比上界2小了,後面怎麼列舉都超不過上界
當高位列舉剛好是上界時,緊跟著的一位就有上界限制
這裡如果千位是2,那麼百位就只能是0了,十位也只能是0或1
(就是得注意一下前導0的問題,判斷比較麻煩,當然,這取決於題目)
因為只控制了上界,所以下界肯定會比left小(應該是0或1)
也就是說統計[1,right]區間的數量和[1,left-1]區間的數量,然後將這兩個數量相減就能得到[left,right]區間的數量了
cout<<
shu_wei_dp
(right)
-shu_wei_dp
(left-1)
;
就拿scoi2009:windy 數 舉栗子
定義windy數字任意相鄰兩位只差大於等於2的數
查詢區間[left,right]之間windy數的個數
這道題可以處理1 ~ left-1的方案數ans[l-1]和1 ~ r的方案數sum[r],則ans=sum[r]-sum[l-1]
注意,這題是不考慮前導0的,所以一定腰避開這個坑(雖然題目已經提示了)
#include
#include
#include
#include
using
namespace std;
typedef
long
long ll
int a,b,len,num[15]
,f[15][
15][2
][2]
;ll dfs
(ll len, ll last,
bool flag,
bool zero)
intsolve
(ll x)
//求出1到x共有多少個windy數
memset
(f,-1,
sizeof f)
;return
dfs(len,11,
1,1)
;//記憶化搜尋
}int
main()
數字動態規劃
如果發現有些數字題目需要處理的資料多,而且單個數處理數字計數時會隨著數的變大越來越麻煩 通常都這樣 就適合這種方法或者這種思想解決問題。因為通常遇到這方面的題目通常會考察乙個連續區間內符合某條件的數,這樣可以將單個數的位操作合一,直接看題目條件內所有的數的條件符合情況,即直接處理所有數可能的所有位以...
基礎演算法之動態規劃 數字DP
數字dp一般用來統計乙個區間 l,r l,r l,r 中滿足條件f i f i f i 的數的個數。條件f i 條件 f i 條件f i 一般與數的大小無關,而與數的組成有關 即數字,個位 十位 百位 因此數的大小對複雜度的影響很小。數字dp本質是對暴力列舉的優化,使得新的列舉方式滿足dp性質,從而...
動態規劃 數字DPwindy
include include include using namespace std define ll long long const int maxn 2e9 10 ll f 20 20 設f i,j 表示由前i位數字構成且最高位數字為j的windy數有多少個 ll a 20 void ini...