數位dp進階(hdu2089,3652)
阿新 • • 發佈:2018-09-30
cin one ger any hdu2089 代碼 num ios egit
之前的文章已經講過如何求1—r中的特殊數,這篇博客就來講些進階操作;
直接看例題(hdu2089):
(題目是中文的我就不寫大意了)
這題與hdu3555最大的區別就是規定了l,不再以1開始;
解決這個問題也很簡單,利用前綴和的思想,先計算1—l-1特殊數的數量,在計算l—r的數量,相減就是答案了;
附上醜陋的代碼:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define int long long 5 constint MAXN=20; 6 int n,r,t,degit[MAXN],dp[MAXN][MAXN],t2,l; 7 int dfs(int pos,int pre,bool limit) 8 { 9 if(pos==0) return 1; 10 if(!limit && dp[pos][pre] != 0) 11 { 12 return dp[pos][pre]; 13 } 14 int up=9; 15 if(limit) up=degit[pos]; 16 int ans=0; 17 for(int i=0;i<=up;++i) 18 if(pre==6&&i==2||i==4) 19 continue; 20 else 21 { 22 ans+=dfs(pos-1,i,limit&&(i==degit[pos])); 23 } 24 if(!limit) 25 { 26 dp[pos][pre] = ans; 27 } 28 return ans; 29 } 30 void solve(inty,int x) 31 { 32 t=0; 33 int xx=x; 34 while(x>0) 35 { 36 ++t; 37 degit[t]=x%10; 38 x=x/10; 39 } 40 int ans2=dfs(t,0,1); 41 t=0; 42 --y; 43 xx=y; 44 while(y>0) 45 { 46 ++t; 47 degit[t]=y%10; 48 y=y/10; 49 } 50 int ans=dfs(t,0,1); 51 printf("%lld\n",ans2-ans); 52 } 53 main() 54 { 55 while(cin>>l>>r) 56 { 57 if(l==0&&r==0) return 0; 58 solve(l,r); 59 } 60 }
例題2(hdu3652):
手(幫)動(你)翻譯(太懶了,不想寫題意)
這題又與上題有些不同,不僅要滿足含13,還要整除13;
具體實現也不難,只要在搜索的同時記錄數字除以13的余數;
怎麽傳遞呢?這又要考小學奧數了,余數的性質;
(4)a與b的和除以c的余數(a、b兩數除以c在沒有余數的情況下除外),等於a,b分別除以c的余數之和(或這個和除以c的余數)。例如,23,16除以5的余數分別是3和1,所以(23+16)除以5的余數等於3+1=4。註意:當余數之和大於除數時,所求余數等於余數之和再除以c的余數。例如,23,19除以5的余數分別是3和4,所以(23+19)除以5的余數等於(3+4)除以5的余數。 (5)a與b的乘積除以c的余數,等於a,b分別除以c的余數之積(或這個積除以c的余數)。例如,23,16除以5的余數分別是3和1,所以(23×16)除以5的余數等於3×1=3。註意:當余數之積大於除數時,所求余數等於余數之積再除以c的余數。例如,23,19除以5的余數分別是3和4,所以(23×19)除以5的余數等於(3×4)除以5的余數。 性質(4)(5)都可以推廣到多個自然數的情形。
太長不想看也不要緊,總結一下就是$a \times 100+b \times 10+c$ % $ d = a \times 100 $%$ d+b \times 10 $%$ d +c $%$ d$;
這有什麽用呢,這個性質可以讓我們在傳遞的時候,只要把余數$\times 10$再加上現在選取的數 mod 13就可以了,最後看是否滿足條件
附上水代碼:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define int long long 5 const int MAXN=20; 6 int n,r,t,degit[MAXN],dp[MAXN][MAXN][MAXN][2]; 7 int dfs(int pos,int pre,bool limit,int mo,bool have,int sum) 8 { 9 if(pos==0) 10 { 11 if(mo==0&&have) 12 { 13 return 1; 14 } 15 else 16 return 0; 17 } 18 if(!limit&&dp[pos][pre][mo][have]!=0) return dp[pos][pre][mo][have]; 19 int up=9; 20 if(limit) up=degit[pos]; 21 int ans=0; 22 for(int i=0;i<=up;++i) 23 if(pre==1&&i==3) 24 ans+=dfs(pos-1,i,limit&&(i==degit[pos]),(mo*10+i)%13,1,sum*10+i); 25 else 26 ans+=dfs(pos-1,i,limit&&(i==degit[pos]),(mo*10+i)%13,have,sum*10+i); 27 if(!limit) dp[pos][pre][mo][have]=ans; 28 return ans; 29 } 30 void solve(int x) 31 { 32 t=0; 33 int xx=x; 34 while(x>0) 35 { 36 ++t; 37 degit[t]=x%10; 38 x=x/10; 39 } 40 printf("%lld\n",dfs(t,0,1,0,0,0)); 41 } 42 main() 43 { 44 while(cin>>r) 45 { 46 solve(r); 47 } 48 }
又這樣水過了一篇博客;
下一篇應該會講一些變式+沒有太大用的優化(立個flag);
數位dp進階(hdu2089,3652)