Today's training is based on bit DP, which can be used for statistics of special types in integer ranges. The method described by the xnozero senior is recursive DP, but in actual coding, there is a kind of memory-based search method for the statistics of the total number.CodeIt will be clearer, reducing the representation of many States. This method is generally used to initialize the process in the same way as the bit-by-bit statistics.
I learned this blog, very inspired: http://www.cppblog.com/Yuan/archive/2011/01/25/139299.aspx
For example, we have three questions for today's training session (the first two are relatively watery) (unfortunately, the question of finding the maximum range in question C is not easy to solve with this elegant code ):
Hoj 3038 tier number: http://acm.hit.edu.cn/judge/show.php? Proid = 3038
The bitwise digit low is always greater than or equal to the upper digit. For example, 123 is a tiered number, but 321 is not. Now we can find the number of tiered numbers between the closed intervals [a, B. (1 <= A, B <= 2 ^ 31)
Considering that each bit of the incremental number meets the requirements of num <PRE, pre is the first bit. You can design the status: DP [POS] [pre], and POS is the current digit, PRE is the value of the first digit. The state transition equation can be DP [I] [J] = sum {DP [I + 1] [k]} (0 <= k <PRE ), however, it is not easy to process the boundary like '9'. You can also add a one-dimensional state to save whether the previous node has reached the maximum value. The main code for using memory-based search is provided here.
Long long DFS (INT POs, int pre, int inf) // The Upper Bound arrival flag of INF storage {If (Pos =-1) return 1; if (! INF & DP [POS] [pre]! =-1) return DP [POS] [pre]; long ans = 0; int end = inf? Digit [POS]: 9; For (INT I = 0; I <= end; I ++) {if (I> = pre) ans + = DFS (POS-1, i, INF & I = END);} If (! INF) DP [POS] [pre] = ans; // note that when the upper bound is reached, the result is incomplete and cannot be returned ans;} long calc (long X) {int Pos = 0; while (x) {digit [POS ++] = x % 10; X/= 10;} return DFS (POS-1, 0, 1 ); // DP array Initialization is-1}
Hoj 3039: http://acm.hit.edu.cn/judge/show.php? Proid = 3039
Find the number of the numbers in the range of [a, B] whose sum of mod n is 0 (1 <= A, B <= 2 ^ 31, 1 <= n <100)
During the same competition, the students reported that this question is very different from the previous recursive statement. Here, the same template of the Memory search is still used, and the status DP [POS] [pre], the Pre here is not the previous number, but the result of adding all the preceding digits to the modulus n, satisfying all the conditions: Pre = (pre + I) % N, here, I is the enumeration of the current number. The implementation of the code is basically the same as that of the previous question. You only need to change the return value of the boundary to return (pre = 0) and remove the updated part of recursion from the judgment, change to ans + = DFS (POS-1, (pre + I) % N, INF & I = END.
There are very few conditions involved in the first two questions. This is a water question. Today's d question is the B Question of the Chengdu cyber competition. It is not very difficult after mastering the techniques of digital DP. See HDU 3652
There are two conditions for this question. One is that the number contains 13, and the number must be a multiple of 13. to construct such a wqb-number, we can divide it into two parts, one is to include the sub-string "13" (refer to the processing of HDU 3555). On the other hand, the record status pre, the initial value is 0, and the subsequent constant satisfies pre '= (Pre * 10 + I) % 13, which will meet _ pre = (Pre * 10 ^ POS + I) % 13, when _ pre is 0, it can be considered that a multiple of 13 is successfully constructed. The key code is as follows:
Long long DFS (INT POs, int pre, int tag, bool inf) {If (Pos =-1) return tag = 2 & Pre = 0; If (! INF & DP [POS] [pre] [tag]! =-1) return DP [POS] [pre] [tag]; long ans = 0; int end = inf? Digit [POS]: 9; For (INT I = 0; I <= end; I ++) {// tag meaning: 0 indicates that the current position is any number and "13" is not displayed in the previous sequence; 1 indicates that "13" is not displayed before and the current position is "1 "; 2 indicates that the previous sequence contains "13 ". int PPRE = (Pre * 10 + I) % 13, ptag = tag; If (TAG = 0 & I = 1) ptag = 1; else if (TAG = 1 & I! = 1) ptag = 0; If (TAG = 1 & I = 3) ptag = 2; ans + = DFS (POS-1, PPRE, ptag, INF & (I = END);} If (! INF) DP [POS] [pre] [tag] = ans; return ans ;}
This categoryAlgorithmBasic Framework:
Init DP [1... n] [1... m] [1... K] to-1
DFS (Pos, pre, Tag, INF)
If (Pos =-1) return _ if_the_result_exist _
If (! INF & DP [POS] [pre] [tag]) return DP [POS] [pre] [tag]
Init ans
Init edge (beg | end)
Repeat (I = 1... to... end) // or beg to end. The dual-boundary problem is too troublesome for the moment.
Do
Modify the pre '& tag'
Ans + = DFS (POS-1, pre ', tag', INF & (I = END) // it seems that the maximum range value problem can be solved using ans = max (DFS, ans), but I have not come up with a complete solution for the moment.
If (! INF)
Modify (DP [POS] [pre] [tag]
Return ans
DFS endp
PS: today's question C is the best value for the upper and lower bounded closed intervals. It is not clear whether I have mastered the memory-based search technology or the limitations of the template application. I need to study it in depth.