1. 程式人生 > >數位dp對於狀態描述與發現的一些感悟

數位dp對於狀態描述與發現的一些感悟

code scanf ble 數字 統計 .cn detail 今天 size

今天刷的數位dp 第一題看了題解以後知道了數位dp的基本板子,寫數位dp的方式(運用記憶化遞歸的方法)已經基本固定。

那麽接下來的難點主要還是對於題目描述的問題,如何抽象成dp中的狀態。就今天刷的題來看,dp數組第一維一般為第i位數,這是數位dp的一般表示數的方式。而數組究竟還要加幾維就要看題目要求的東西。

如下題:

http://acm.hdu.edu.cn/showproblem.php?pid=3709

題意即求:

對於某個 number,你可以 fix a pivot 在某位,然後如果分成的左右兩部分的 sigma(d[i] * | i - fixloc |)相等,則它是 Balanced Number。

統計區間 [a,b] 中Balance Number 的個數。(引用https://blog.csdn.net/dgq8211/article/details/9302069)

這個題目問的是滿足條件的最大總數。故dp數組(不管幾維)=當前狀態的最大總數。

那麽問題用數位dp 關註數字本身屬性的思想,可以抽象出一個狀態即支點的位置[x]。

//除此,與問題結果直接相關的即支點兩端的力矩差[sum]。

因為數位dp是(貌似dp都是)枚舉所有情況再找到最優解的,所以一定會有一個狀態為問題所要求滿足的東西。以該題看,條件要求滿足的就是支點兩邊的力矩差=0,那麽力矩差就一定是dp數組裏的一維了。

綜上兩個狀態發現最大總數就是各個點為支點所有滿足力矩差為0的情況的總和sum。

可以將所有的情況列出。此時思考dp數組結束,即dp[pos][x][sum]。

找到正確的dp數組後就可以開心的套板子再調整細節等AC了~~~

(這題AC代碼可以從上面的鏈接看,我偷懶不發了)

其實如果能將問題抽象為數學函數那麽能更加直觀的發現狀態,如題目要求找到(0,n)上所有能被13整除的數的總數那滿足要求的x=cigma(n%13==0) dp數組即cigma(),狀態就是數n和n%13,(也就是自變量和與自變量相關的運算)。

可得dp[pos][13]。

#include<cstdio>
#include<cstring>
int dp[10][15];
int digit[10]; int n; int dfs(int pos,int mod ,int limit) { if(pos==-1)return mod==0; if(!limit&&dp[pos][mod]!=-1)return dp[pos][mod]; int tmp=0,mm,; int up=limit?digit[pos]:9; for(int i=0;i<=up;i++) { mm=(mod*10+i)%13; tmp+=dfs(pos-1,mm,limit&&i==digit[pos]); } if(!limit)dp[pos][mod]=tmp; return tmp; } int solve(int x) { int k = x; int pos = 0; while(k) { digit[pos++]=k%10; k/=10; } return dfs(pos-1,0,1); } int main() { memset(dp,-1,sizeof(dp)); while(~scanf("%d",&n)) { printf("%d\n",solve(n)); } return 0; }

數位dp對於狀態描述與發現的一些感悟