1. 程式人生 > >數位dp進階(hdu2089,3652)

數位dp進階(hdu2089,3652)

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 const
int 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(int
y,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)