题意:
- 给你个矩阵,每个位置是空或者不空
- 每两个相邻空的位置,可以放一个木条
- 有q次询问,每次问你一个子矩阵中,放一根木条有多少种放法
O(2wh+q(w+h)) 约为1e7
定义好状态即可:/f[i][j] 第i行横着放,前j列&&以第j列为终点(第2个'.'在第j列上)连续2个.的个数
//cos A=(b2+c2-a2)/2bc
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=6e2+20;
char g[N][N];
int h,w;
int f[N][N],d[N][N];//f[i][j] 第i行横着放,前j列&&以第j列为终点(第2个'.'在第j列上)连续2个.的个数
void init()
{
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
for(int i=1;i<=h;i++)
{
f[i][0]=0;
f[i][1]=0;
for(int j=2;j<=w;j++)
{
if(g[i][j]=='.'&&g[i][j-1]=='.')
f[i][j]=f[i][j-1]+1;
else
f[i][j]=f[i][j-1];
//cout<<f[i][j]<<' ';
}
//cout<<endl;
}
for(int j=1;j<=w;j++)
{
d[0][j]=0;
d[1][j]=0;
for(int i=2;i<=h;i++)
{
if(g[i][j]=='.'&&g[i-1][j]=='.')
d[i][j]=d[i-1][j]+1;
else
d[i][j]=d[i-1][j];
}
}
}
int main()
{
while(scanf("%d%d",&h,&w)!=EOF)
{
for(int i=1;i<=h;i++)
scanf("%s",g[i]+1);
init();
int q;
scanf("%d",&q);
//q<=1e5 1<=w,h<=500 3秒时限
//O(2wh+q(w+h)) 1e7
while(q--)
{
int r1,c1,r2,c2;
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
int ans=0;
for(int i=r1;i<=r2;i++)
ans+=f[i][c2]-f[i][c1];
for(int j=c1;j<=c2;j++)
ans+=d[r2][j]-d[r1][j];
cout<<ans<<endl;
}
}
return 0;
}