動態規劃之數字dp

2021-10-03 05:01:56 字數 3010 閱讀 8477

數字dp,字面意思理解就是在數字的每一位上面去dp,動態規劃一般有兩種:遞推,記憶化搜尋(dfs)。這裡就是用的記憶化。

一般這種用在計數上面,對那些數字上面有限制的計數。

這裡上一道模板題:

題中就是要你統計1—n裡有「49」的個數。

dp[pos][sta]表示到第pos位,狀態為sta的總數。

我們一般是從高位往低位計數。我們這裡的狀態本來可以是10種(0,1,2,。。。9)但是我們可以把他們分為兩種(為4的,不為4的)

如果我們當前位為4,那麼下一位就不能為9.

#include

#include

#include

#include

#include

using namespace std;

#define ll long long

ll dp[20]

[2];

int digit[20]

;//分解x,將各個位賦值給digit陣列

ll solve

(ll x)

//這裡limit為true,是因為我們第一位的前面想象為0,那麼就是有上界了(0為上界)。

return

dfs(pos,false,true);}

//pos表示當前第幾位

//sta表示前一位是否是4

//limit表示是否到達上界

ll dfs

(int pos,bool sta,bool limit)if(

!limit) dp[pos]

[sta]

=cnt;

return cnt;

}int

main()

}}

為什麼返回值那裡要if(!limit),我們假設上界是230,求1–230的不含「33」的個數。那麼我們百位訪問0的時候,因為沒有達到上界(2),所以十位我們可以訪問0-9,當十位訪問3的時候,個位我們可以訪問0,1,2,4(不能有「33」),所以有4個。但是當我們百位訪問2的時候,到達上界了,就是說十位,個位我們不能取0-9了,十位只能取到3,個位只能取到0。當我們十位取到3的時候,這是如果我們沒有(!limit),我們前面算到dp[0][1](當前位 為 個位,前面一位是3),我們會直接返回4,但是這裡我們只能訪問0,因為不能超過230。所以得limit。

後面的記憶化也要limit也是這樣。

hdu 4507

題目要求的是與7無關的數的平方和。這個數字dp不是計數的,而是求平方和的。

dp[pos][mod1][mod2]為當前位為pos,各個位數的和模7,數的和模7

首先我們先設定狀態,題目的要求:

1,沒有7,這個直接在迴圈裡面判斷進行了.

2.各位數之和不是7的倍數

3.這個數不是7的倍數。

2.3這兩個得在遞迴裡面去加,然後分情況。

可以對7取模,就有餘數為0,就是7的倍數,不為0,就是可以找的數。

這是條件,接下來看要求的平方和。

我們算乙個數的平方和,比如123,145,134這些都是合法的數,那求平方和就是,(100+23)^2+(100+45) ^2+(100+34) ^2=3100 ^2+2100*(23+45+34)+(23 ^2+45 ^2+34 ^2);

這樣我們假設我們求到pos為百位1的時候,我們求的平方和就為

從十位開始後面的數(加上百位後的各種條件合法後)的個數乘以

ipower[i]+ 2 * i power[i] * 十位後的數的總和 +十位後數的平方和。

temp為低位,ans為高位。可以看做temp為十位後面的,ans為百位

其實就是:

ans.cnt+=temp.cnt (合法的數)

ans.sum1+=temp.cnt * i * power[pos]+temp.sum1 (各個數的和)

ans.sum2+=i * power[pos] * i * power[pos] * temp.cnt+temp.sum2+2 * i * power[pos] * temp.sum1(各個數平方和)

為什麼要乘以個數,就是為百位1後面 有多個合法的數。

其他的都和簡單的數字dp差不多了。

要注意的點

solve(y)可能比solve(x-1)小,所以要+mod後取模,比如(6-3)%5=3

,但是6%5-3%5=-2, (-2+5)%5=3;

#include

#include

#include

#include

#include

#define ll long long

#define mod 1000000007

using namespace std;

struct nodedp[20]

[10][

10];int digit[20]

;ll power[25]

;node dfs

(int pos,

int mod1,

int mod2,bool limit);if

(mod1&&mod2) temp.cnt=1;

return temp;}if

(!limit&&dp[pos]

[mod1]

[mod2]

.cnt!=-1

)return dp[pos]

[mod1]

[mod2]

;int up=limit?digit[pos]:9

; node ans=

;for

(int i=

0;i<=up;i++)if

(!limit) dp[pos]

[mod1]

[mod2]

=ans;

return ans;

}ll solve

(ll x)

return

dfs(pos,0,

0,true)

.sum2%mod;

}int

main()

}}

基礎演算法之動態規劃 數字DP

數字dp一般用來統計乙個區間 l,r l,r l,r 中滿足條件f i f i f i 的數的個數。條件f i 條件 f i 條件f i 一般與數的大小無關,而與數的組成有關 即數字,個位 十位 百位 因此數的大小對複雜度的影響很小。數字dp本質是對暴力列舉的優化,使得新的列舉方式滿足dp性質,從而...

模板 動態規劃 數字dp

includeusing namespace std define ll long long int a 20 ll dp 20 20 可能需要的狀態1 20 可能需要的狀態2 不同題目狀態不同 ll dfs int pos,int state1 可能需要的狀態1 int state2 可能需要的狀...

動態規劃 數字dp入門(二)

較為簡單的數字dp只會涉及到每一位上的數字變化,如比較相鄰數字差,是否含有某個數字等等,在這種情況下一般用dp i j 就可以,i表示數字長度,j用來表示首位數字。如果題目要求對數字整體進行考慮,我們不能對各個位置上的數直接判斷,就需要對每位之前判斷過的數進行記憶化儲存。題目hdu3652 numb...