题意
- 给你个矩阵,每个位置是空或者不空
- 每两个相邻空的位置,可以放一个木条
- 有q次询问,每次问你一个子矩阵中,放一根木条有多少种放法
思路
- dp(i,j),表示左上角,这块的放法数,mark(i,j) 表示当前位置是否为空(1为空)
- dp(i,j) = dp(i-1,j) + dp(i,j-1) - dp(i-1,j-1) + (mark(i,j) && mark(i-1,j) ) + (mark(i,j) && mark(i,j-1) )
- 然后针对查询,这里要注意了,比较麻烦,需要考虑,在边界上的格子,是否可以和外面的一个组成一个可以放的情况,这些需要被删去。。所以复杂度为O(Q*(w+h))~具体的参见代码吧~
实现
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 505;
char mark[maxn][maxn];
ll dp[maxn][maxn];
int main(){
int n,m;
cin>>n>>m;
getchar();
for (int i=1;i<=n;i++){
gets(mark[i]+1);
}
dp[1][1] = 0;
for (int i=2;i<=m;i++){
if (mark[1][i] == '.' && mark[1][i-1] == '.'){
dp[1][i] = dp[1][i-1] + 1;
}
else{
dp[1][i] = dp[1][i-1];
}
}
for (int i=2;i<=n;i++){
if (mark[i][1] == '.' && mark[i-1][1] == '.'){
dp[i][1] = dp[i-1][1] + 1;
}
else{
dp[i][1] = dp[i-1][1];
}
}
for (int i=2;i<=n;i++){
for (int j=2;j<=m;j++){
dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1];
if (mark[i][j] == '.' && mark[i-1][j] == '.'){
dp[i][j]++;
}
if (mark[i][j] == '.' && mark[i][j-1] == '.'){
dp[i][j]++;
}
}
}
int Q;
cin>>Q;
int x1,y1,x2,y2;
while (Q--){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
ll ans = dp[x2][y2] + dp[x1-1][y1-1] - dp[x2][y1-1] - dp[x1-1][y2];
if (y1 >= 2){
for (int i=x1;i<=x2;i++){
if (mark[i][y1] == '.' && mark[i][y1-1] == '.'){
ans--;
}
}
}
if (x1 >= 2){
for (int i=y1;i<=y2;i++){
if (mark[x1][i] == '.' && mark[x1-1][i] == '.'){
ans--;
}
}
}
cout << ans << "\n";
}
return 0;
}