Nanjing University of Science and Technology is celebrating its 60th anniversary. In order to make room for student activities, to make the university a more pleasant place for learning, and to beautify the campus, the college administrator decided to start construction on an open space.
The designers measured the open space and come to a conclusion that the open space is a rectangle with a length of n meters and a width of m meters. Then they split the open space into n x m squares. To make it more beautiful, the designer decides to cover the open space with 1 x 1 bricks and 1 x 2 bricks, according to the following rules:
1. All the bricks can be placed horizontally or vertically
2. The vertexes of the bricks should be placed on integer lattice points
3. The number of 1 x 1 bricks shouldn’t be less than C or more than D. The number of 1 x 2 bricks is unlimited.
4. Some squares have a flowerbed on it, so it should not be covered by any brick. (We use 0 to represent a square with flowerbet and 1 to represent other squares)
Now the designers want to know how many ways are there to cover the open space, meeting the above requirements.
Input
There are several test cases, please process till EOF.
Each test case starts with a line containing four integers N(1 <= N <= 100), M(1 <= M <= 10), C, D(1 <= C <= D <= 20). Then following N lines, each being a string with the length of M. The string consists of ‘0’ and ‘1’ only, where ‘0’ means the square should not be covered by any brick, and ‘1’ otherwise.
Output
Please print one line per test case. Each line should contain an integers representing the answer to the problem (mod 10 9 + 7).
Sample Input
1 1 0 0 1 1 1 1 2 0 1 1 1 2 1 1 2 1 2 11 1 2 0 2 01 1 2 0 2 11 2 2 0 0 10 10 2 2 0 0 01 10 2 2 0 0 11 11 4 5 3 5 11111 11011 10101 11111
Sample Output
0 0 1 1 1 2 1 0 2 954
不懂轮廓线的先去看看轮廓线的定义~~:
然后这样的话,与基本的轮廓线dp多了一个两个东西,一个是可以放置制定数量的1*1的小木块,另一个是有位置不可以防止。对于那些不可以防止的地方我们把他们看成放置好的,且不计入限制数量1*1的小木块就好了。
另一个问题就是如果开全部的dp数组会mle,这样的话就需要滚动数组这个概念了。~~
然后对于放置木块的情况:
1.对于放置1*1的木块,他的上方必须是已经填充好的情况。
2.对于横放1*2的木块,他的左边必须没有防止木块,且上方必须放置着木块。
3.对于竖放1*2的木块,(如果他的上方有了木块,那这个地方就不能放1*2木块了,取空,如果上面没有,就可以继续进行状态转移);
4.对于不能放置的地方,我们可以在每次特殊处理就好(当作不计入数量的1*1木块)
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n, m, c, d, big;
int pre = 0, now = 1;
long long dp[2][22][1222];//滚动数组。
char mp[105][15];
void init() {
big = (1 << m);
memset(dp[now], 0, sizeof(dp[now]));
dp[now][0][big - 1] = 1;
for (int i = 0; i < n; i++)
cin >> mp[i];
}
int main() {
ios::sync_with_stdio(0);
while (cin >> n >> m >> c >> d) {
init();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
swap(now, pre);
memset(dp[now], 0, sizeof(dp[now]));
if (mp[i][j] != '0') {
for (int k = 0; k <= d; k++) {
for (int s = 0; s < big; s++) {
if (k && (s & 1 << j))
dp[now][k][s] = (dp[now][k][s] +
dp[pre][k - 1][s]) % mod;
if (j && !(s & 1 << (j - 1)) && (s & 1 << j))
dp[now][k][s | 1 << (j - 1)] = (dp[now][k][s | 1 << (j - 1)] +
dp[pre][k][s]) % mod;
dp[now][k][s ^ 1 << j] = (dp[now][k][s ^ 1 << j] +
dp[pre][k][s]) % mod;
}
}
}
else {
for (int k = 0; k <= d; k++) {
for (int s = 0; s < big; s++) {
if (s & 1 << j)
dp[now][k][s] = (dp[now][k][s] + dp[pre][k][s]) % mod;
}
}
}
}
}
long long int ans = 0;
for (int i = c; i <= d; i++)
ans = (dp[now][i][big - 1] + ans) % mod;
cout << ans << endl;
}
return 0;
}