數字dp是什麼?以前總覺得這個概念很高大上,最近閒的沒事,學了一下發現確實挺神奇的。
hdu 2089 "不要62"
乙個數字,如果包含'4'或者'62',它是不吉利的。給定m,n,0這題的資料範圍比較小,只有1e6,理論上暴力也是可以解的。但數字dp的題目資料範圍通常很大,往往達到1e18甚至更大,暴力法o(n)顯然會tle。這個時候需要一種時間複雜度近似o(logn)的演算法。仔細思考一下,其實可以使用排除法。從高位到低位依次排除0~1e6中不符合條件的數。
舉個例子,1~999999中不包含4的數,步驟如下:
1.先排除6位數中最高位是4的數,即400000~499999,只需要判斷最高位,就排除了10萬個數。
2.接著排除次高位是4的數(此時預設最高位不是4),比如最高位是1時可以排除140000149999,共1萬個。注意,首位**可以是0**,此時相當於考慮000000099999(初學者可能有點不理解,看完後面一些不考慮前導0的題就懂了)。
3.同理,繼續排除4位數,3位數,直到結束。
數字dp是對數字的「位」進行的和計數有關的dp,數的每乙個位稱為數字,乙個數有個位、十位、百位、千位……數字dp用來解決和數字操作有關的問題,比如某區間內數字和,特定數字問題等。這些問題的數字範圍通常很大,無法暴力解決,必須用接近o(logn)的演算法。通過dp對「數字」操作,記錄算過的區間的狀態,用於後續計算快速篩選數字。
那麼這道題用數字dp怎麼實現呢?數字dp一般有兩種方法,一種是dp預處理亂搞,另一種是記憶化dfs。前者不適合模板化,而後者效率高,模板易記,可以快速上手。
#include using namespace std;
typedef long long ll;
ll dp[20][20];
int a[20];
ll n,m;
// pos:當前到第幾位 pre:上一位數字是什麼 lead:是否有前導0 limit:是否有上界限制 (引數通常有pos和limit,是否有lead看題目要求,此外還有可能增加其他引數)
ll dfs(int pos,int pre,bool lead,bool limit)
}if(!lead && !limit) dp[pos][pre] = ans;
return ans;
}ll solve(ll x)
memset(dp,-1,sizeof(dp)); //初始化dp陣列
return dfs(len,0,true,true); //從高位向低位列舉
}int main()
這裡解答幾個初學者常見的疑問
下面我們通過模板來秒掉這道題目吧
題目鏈結
dp[pos][sta]表示第pos位前一位是6(sta = 1),或者不是6(sta = 0)時滿足條件的數的數目,這裡由於數的前一位是否是6會對答案構成影響,所以只需要在統計時把答案分成兩類。
#include using namespace std;
typedef long long ll;
int n,m;
ll dp[20][2];
int a[20];
int dfs(int pos,int pre,int sta,bool limit)
if(!limit) dp[pos][sta] = sum;
return sum;
}int solve(int x)
return dfs(len,-1,0,true);
}int main()
return 0;
}
題目鏈結
這題定義了乙個叫"k好數"的概念,即該數在k進製下任意相鄰兩位的數不能相鄰(即相差不能等於1),然後要統計l位k進製中k好數的數目。這道題的坑點在於要考慮前導0的影響,比如4進製下的兩位數,11,20是k好數,但是32不是k好數。但如果我們求的是4進製下的一位數,問題就來了,如果沒有lead這個引數,1這個數就不會被統計,因為傳參時預設前一位是0,而0和1相鄰,這個時候只需要加乙個判斷即可。
#include using namespace std;
typedef long long ll;
ll mod = 1e9 + 7;
ll dp[105][105];
int k,l;
ll dfs(int pos,int pre,bool lead,bool limit)
}if(!lead && !limit) dp[pos][pre] = ans;
return ans;
}ll solve(int len)
int main()
題目鏈結
這題定義了乙個叫b數的東西,這個數含"13"這個串並且可以被13整除。難點在於怎麼儲存被13整除這個狀態,其實很簡單,再加乙個引數tot記錄餘數,每次列舉%一下13,當pos=0時判斷即可。
#include using namespace std;
typedef long long ll;
ll dp[15][10][13][2];
int a[15];
ll n;
ll dfs(int pos,int pre,int tot,int ok,bool limit)
if(!limit) dp[pos][pre][tot][ok] = ans;
return ans;
}ll solve(ll x)
return dfs(len,0,0,false,true);
}int main()
題目鏈結
這道題挺有意思的,要統計的是每個數二進位制下1的個數sum(i),然後求sum(1)到sum(n)的累乘。
我們要轉換一下思維,n上限是1e18,意味著這個數的二進位制最多有50位,即最多就50個1,我們分別統計二進位制下有乙個1,兩個1,三個1……五十個1的數的個數,然後用快速冪進行優化,問題就迎刃而解了。
#include using namespace std;
typedef long long ll;
const ll mod = 1e7 + 7;
ll dp[51][51][51];
int a[51];
ll ans[51];
ll n;
ll poww(ll x,ll y,ll p)
return ans;
}//位置 當前統計到的1的個數 目標要統計的1的個數 上界限制
ll dfs(int pos,int tmp,int tot,bool limit)
if(!limit) dp[pos][tmp][tot] = sum;
return sum;
}ll solve(ll x)
memset(dp,-1,sizeof(dp));
//這裡是乙個很巧妙的優化 分別統計二進位制中1的個數為i的數的個數,然後快速冪優化
for(int i = 1;i <= len;i++)
return sum;
}int main()
題目鏈結
這道題大意是求某區間內數字0-9出現的次數。我大概的想法是,分別統計區間內存在1個1,2個1,3個1……的數的個數,存在1個2,2個2,……,1個9,2個9,……的數的個數,然後求累加,當然題解有更好的方法,以下僅供參考(注意前導0的處理,否則統計0的時候會出錯)
#include using namespace std;
typedef long long ll;
ll dp[15][15][15];
int a[15];
ll ans[10][15];
ll total[10];
ll n,m;
int num;
//前導0很關鍵!!
ll dfs(int pos,int now,int tot,bool lead,bool limit)
if(!limit && !lead) dp[pos][now][tot] = sum;
return sum;
}ll solve(ll x,bool ok)
memset(dp,-1,sizeof(dp));
memset(ans,0,sizeof(ans));
for(int i = 0;i < 10;i++)
}}int main()
題目鏈結
題目的大意是求l-r區間內每個數的各位數字和,假設這個數共len位,那麼它的各位數字之和不會超過9*len(因為每位數字最大是9),我們只需要從小到大列舉統計即可,本質思想和上面的題目是一樣的。
#include using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int t;
ll n,m;
ll dp[20][180][180],ans[180];
int a[20];
//位置 當前的各位和 目標和 上界限制
ll dfs(int pos,int now,int tot,bool limit)
if(!limit) dp[pos][now][tot] = sum;
return sum;
}ll solve(ll x)
//統計各位和為1-9*len的所有情況
for(int i = 1;i <= 9 * len;i++)
return sum;
}int main()
return 0;
}
蒟蒻的第一篇blog,有錯還請各位神犇指出~~ systemtap embedded C 踩坑筆記
官方文件 systemtap的embedded c中,不能 include 也不能用printf和print。那怎麼列印呢?用stap printf。用法與printf一樣。還可以訪問cript中的全域性變數。官方文件中的示例 global var global var2 100 function ...
Aggregation MongoDB踩坑記錄
對某些篩選條件進行分頁查詢,開始每一頁的有效data都不足pagesize,最後發現,aggregation 的pipeline是有先後順序的。錯誤 agg aggregation.newaggregation aggregation.skip curpage 1 pagesize aggregat...
feign踩坑 通過Feign上傳檔案(踩坑)
引入依賴 org.springframework.cloud spring cloud starter openfeign 服務提供者 restcontroller public inte ce fileuploadservice commonresultuploadfile requestpart...