小白演算法練習 數字dp模板

2021-08-07 06:17:03 字數 2490 閱讀 8992

**:

數字dp其實是很靈活的,所以一定不要奢求一篇文章就會遍所有數字dp的題,這一篇只能是講清楚一種情況,其他情況遇到再總結,在不斷總結中慢慢體會這個思想,以後說不定就能達到一看到題目就能靈活運用的水平。(其實dp都是這樣……)

這一篇要說的數字dp是一道最簡單的數字dp:

題目大意:多組資料,每次給定區間[n,m],求在n到m中沒有「62「或「4「的數的個數。

如62315包含62,88914包含4,這兩個數都是不合法的。0試想:我們如果能有乙個函式count(int x),可以返回[0,x]之間符合題意的數的個數。那麼是不是直接輸出count(m)-count(n-1)就是答案?

好,那麼下面我們的關注點就在於怎麼做出這個函式。我們需要乙個陣列。(dp原本就是空間換時間)

我們設乙個陣列f[i][j],表示i位數,最高位是j的數,符合題意的數有多少個。比如f[1][2]=1; f[1][4]=0; f[2][6]=8 (60,61,63,64,65,66,67,68,69).

我們先不關注這個f有什麼用,我們先關注f本身怎麼求。首先f[1][i]=0(if i==4),f[1][i]=1(if i!=4) (0<=i<=9)。這一步是很顯然的,那麼根據這個題的資料範圍,只需要遞推到f[7][i]就夠用了。那麼稍微理解一下,可以想出遞推式:

f[i][j]=

if (j==4) f[i][j]=0

else if (j!=6) f[i][j]=σf[i-1][k] (k=0,1,2,3,4,5,6,7,8,9)

else if (j==6) f[i][j]=σf[i-1][k] (k=0,1,3,4,5,6,7,8,9)

上面的式子也是很顯然的,如果覺得不顯然可以這樣想:i位數,最高位是j的符合條件的數,如果j是4,肯定都不符合條件(因為題目不讓有4),所以直接是0;如果j不是6,那麼它後面隨便取,只要符合題意就可以,所以是f[i-1][k],k可以隨便取的和;如果j是6,後面只要不是2就行,所以是f[i-1][k],k除了2都可以,求和。

這裡要說明一下,認為00052是長度為5,首位為0的符合條件的數,052是長度為3首位為0符合條件的數。

那麼現在我們已經得到了f陣列,再重申一下它的含義:i位數,最高位是j的數,符合題意的數有多少個。

現在我們就要關注怎麼利用f陣列做出上面我們說的那個函式count(int x),它可以求出[0,x]中符合題意的數有多少個。

那麼我們做這樣乙個函式int solve(int x) 它可以返回[0,x)中符合題意的有多少個。那麼solve(x+1)實際上與count(x)是等價的。

那麼現在問題轉化成了:小於x,符合題意的數有多少個?

很簡單,既然小於,從最高位開始比,必定有一位要嚴格小於x(前面的都相等)。所以我們就列舉哪一位嚴格小於(前面的都相等)。

假設我們現在把x分成了a1,a2,...,al這樣乙個陣列,長度為l,al是最高位。

那麼結果實際上就是這樣:長度為l,最高位取[0,al-1]的所有的符合題意數的和;再加上長度為l-1,最高位取al,次高位取[0,al-1-1]的所有符合題意數的和;再加上……;一直到第一位。

上面有一句話之所以標粗體,是因為這句話並不是對的,但是為了好看,就先這樣寫著。因為我們還需要考慮這種情況:最高位al如果是4,那麼這句話直接就可以終止了,因為粗體這句話前面的那句話「最高位取al」是不能成立的。還要考慮這種情況:最高位al如果是6,那麼這裡並不是能取[0,al-1-1]的所有(不能取2)。加上這些條件之後就很嚴謹了。

把上面的漢字對應到題目裡,就是我們前面求出來的f[l][0..al-1]  f[l-1][0..al-1-1],所以稍加思索之後就能寫出程式了。

/*分類:數字dp 

思路: 乙個區間內不能出現4,或者連續的62 

we are giant.

create by songdan_lee

*/#include

#include

const

intmaxn=10;  

long

long

f[maxn][10];  

void

getdp()  

else

}  }  }   

inta[maxn];  

long

long

solve(

intn)  

a[a[0]+1]=0;  

long

long

ans=0;  

for(

inti=a[0];i>=1;i--)  

return

ans;  

}  int

main()  

}  /*

打表#include

int a[1000000]=;

int main()

while(scanf("%d%d",&n,&m)!=eof&&n!=0||m!=0)

printf("%d\n",a[m]-a[n-1]);

} */

數字DP入門 數字DP模板

數字dp是一種計數用的dp,一般就是要統計乙個區間 le,ri 內滿足一些條件數的個數。所謂數字dp,字面意思就是在數字上進行dp咯。數字還算是比較好聽的名字,數字的含義 乙個數有個位 十位 百位 千位.數的每一位就是數字啦!之所以要引入數字的概念完全就是為了dp。數字dp的實質就是換一種暴力列舉的...

數字DP練習

數字dp模板 hdu2089 不要62 題意 求區間中不含62且不含4的數的個數 include include includeusing namespace std int dp 20 10 int a 20 sta 記錄上一位數是否是6 int dfs int pos,int sta,bool ...

數字dp 模板

dp pos,狀態變數.限制布林 if limit dp 狀態 a 已經求出對應狀態值下的結果了 記錄下來 return a 所以 數字dp其實就是一種求解有關於l到r有多少個符合條件的數目類似的統計問題的解題思路 一遍遍數字列舉太慢 不如我們根據條件列舉數字 數字dp本質上是記憶化搜尋 我們需要在...