题目链接:
http://community.topcoder.com/stat?c=problem_statement&pm=11492题目大意:
将一个矩阵涂成黑白两色,现有一些格子已经被指定为黑色,有些格子已经被指定为白色。
问有多少种给未涂色格子涂色的方法,能使得两种颜色所组成的图形都是“凸包”。
算法:
不妨考虑一种简单的凸包形式,即对于每一行,白格子都在左边,黑格子都在右边,且自上到下白格子的数目逐行减少(非增)。
则计算出每一行的白格子至少延伸到哪儿和至多延伸到哪儿,再用很常见的递推DP的方式去做就可以了。那么相应对称的共有四种这样的凸包形式,要分别计算。
最后要去掉会被重复计算的部分。
代码:
#include <string>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <climits>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int maxn = 60;
long long dp[maxn][maxn], sum[maxn][maxn];
int l[maxn], r[maxn];
const long long MOD = 1000000007LL;
class TwoConvexShapes
{
public:
long long solve(vector <string> &grid, char ch, bool rev)
{
int n = grid.size();
int m = grid[0].size();
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
int lim = 0;
long long ans = 0;
int maxl = 0, minr = m;
for (int i = 0; i < n; i ++)
{
for (l[i] = m - 1; l[i] >= 0; l[i] --)
{
if (grid[i][l[i]] == ch)
{
break;
}
}
for (r[i] = 0; r[i] < m; r[i] ++)
{
if (grid[i][r[i]] != ch && grid[i][r[i]] != '?')
{
break;
}
}
if (l[i] != -1)
{
lim = i;
}
maxl = max(maxl, l[i]);
minr = min(minr, r[i]);
}
for (int i = r[0] - 1; i >= max(0, l[0]); i --)
{
dp[0][i] = 1;
}
for (int i = 0; i < n; i ++)
{
for (int j = r[i] - 1; j >= max(l[i], 0); j --)
{
if (i > 0)
{
if (j == r[i] - 1)
{
dp[i][j] = sum[i - 1][j];
}
else
{
dp[i][j] = (dp[i - 1][j] + dp[i][j + 1]) % MOD;
}
}
}
for (int j = m - 1; j >= 0; j --)
{
sum[i][j] = (dp[i][j] + sum[i][j + 1]) % MOD;
}
if (i >= lim)
{
ans = (ans + sum[i][max(l[i], 0)]) % MOD;
if (rev && dp[i][m - 1] && i < n - 1)
{
ans --;
}
}
}
if (rev)
{
ans -= max(minr - maxl, 0);
}
return ans;
}
int countWays(vector <string> grid)
{
int n = grid.size();
long long ans = solve(grid, 'W', false);
for (int i = 0; i < n; i ++)
{
reverse(grid[i].begin(), grid[i].end());
}
ans = (ans + solve(grid, 'W', true)) % MOD;
ans = (ans + solve(grid, 'B', true)) % MOD;
for (int i = 0; i < n; i ++)
{
reverse(grid[i].begin(), grid[i].end());
}
ans = (ans + solve(grid, 'B', false)) % MOD;
return (int)ans;
}
};