Extending Binary Strings with DP
All the examples below use Distributing DP to extend the strings. If you’ve only solved problems with Receiving DP so far, this style might be difficult to comprehend. You can solve ABC179D: Leaping Tak and ABC335F: Hop Sugoroku in O(n^2)
to get accustomed to this style of DP. I also created a video editorial for the latter.
As a refresher, this is Receiving DP
dp[i][j] = something
This is Distributing DP
dp[i + x][j + y] += something + dp[i][j] + otherthing
Find the number of binary strings of length n
.
Define dp[i]
to be the number of binary strings of length i
. You can extend this string by appending either a 0
or 1
. Hence,
// Append a zero.
dp[i + 1] += dp[i]
// Append a one.
dp[i + 1] += dp[i]
You can find the code here
Call a binary string good if it has no consecutive zeroes. Find the number of good binary strings of length n
.
If you define dp[i]
to be the number of good binary strings of length i
, you won’t be able to extend this string without knowing the character at the last position. This hints us that we also need to track the last character as a parameter in our DP.
Define dp[i][char]
to be the number of good binary strings ending at char
. If char = 1
, we can append either a 0
or 1
, but if char is 0
, we are forced to append a 1
.
// Append a 1
dp[i + 1][1] += dp[i][1]
dp[i + 1][1] += dp[i][0]
// Append a 0
dp[i + 1][0] += dp[i][1]
You can find the code here
Call a binary string good if it doesn’t contain k
consecutive zeroes as a substring. Find the number of good binary strings of length n
.
Just tracking the last character isn’t sufficient anymore. We can only safely extend the string when we know the count of suffix zeroes. Define dp[i][x]
to be the number of good strings that has x
suffix zeroes. Then, if x == k - 1
, we are forced to append a 1
, else we can append either a 0
or 1
. Notice that if you append a 0
, the suffix zero count increses, but if you append a 1
, the suffix zero count is reset.
// Append a 1.
dp[i + 1][0] += dp[i][x]
// Append a 0.
if(x + 1 < k) {
dp[i + 1][x + 1] += dp[i][x]
}
You can find the code here
Call a binary string good if it doesn’t k
consecutive zeroes as a substring and it has no substring 000...1...000
such that if there are x
zeroes to the left of 1 and y
zeroes to the right of 1, then x + y
should not be equal to k
. Find the number of good binary strings of length n
.
Now, tracking the count of suffix zeroes is not sufficient anymore, because you can only extend the string if you also know the count of zeroes to the left of the last occurrence of 1.
Define dp[i][x][y]
to be the number of good strings whose suffix has x
zeroes, followed by a 1
, followed by y
zeroes. Then, you can append 1 anytime, but you can append a 0 only if x + y + 1 != k
. If you append a 1
, the suffix zeroes would be reset, and x
would be replaced by y
. If you append 0
, only y
would increase.
// Append a 1.
dp[i + 1][y][0] += dp[i][x][y]
// Append a 0.
if(x + y + 1 < k) {
dp[i + 1][x][y + 1] += dp[i][x][y]
}
You can find the code here
Remember, earlier we told you that extending a string is not possible without storing additional states such as x
and y
? Turns out, it is indeed possible, if you do the transitions in bulk.
For the K-Zero Stream (Hard Version) : Define dp[i][x]
to the be the number of good binary strings that has a suffix consisting of x
zeroes. We are not allowed to track y
anymore. So, to ensure that x + y < k
, we need to do all transitions at once because we would forget those information if we do it step by step.
If the current string consists of x
suffix zeroes, then we can try to extend this string by adding 1
or 10
or 100
or 1000
or 1000...
where the new string has a suffix consisting of y
zeroes. Then, dp[i][x]
would contribute to dp[i + 1 + y][y]
for all y
such that x + y < k
.
// Append 1 followed by y zeroes
for y = 0; x + y < k; y++ {
dp[i + 1 + y][y] += dp[i]
}
You can find the code here
If you’re looking for some more problems where dropping a parameter seems impossible at first, but is actually possible, try ABC334F: Christmas Present 2. I also created a video editorial for it. Here, you might think that it’s impossible to distribute gifts if you don’t keep a parameter to track how many presents are remaining when you reach the i-th
child, but you’ll love the cleverness of the final DP definition.
Easy Version : Problem Link Original Version : Problem Link
If you’ve really understood the tutorial so far, you should close this page and solve this problem in O(n^3)
time and O(n^2)
space by yourself. You can come back to it for the final optimized solution.
How to drop parameter for binary strings no consecutive zeroes?
How are strings with no consecutive zeroes and Fibonacci number related?
How to drop parameter for no k zero stream?
How to find strings with atleast 3 Consecutive zeroes?
Thanks to aryanc403
for showing me the trick of dropping parameters from DP and doing transitions in bulk.