传送门(校内)
题目大意
一个有n∗m 个格子的矩阵,每个格子用“.”或“#”表示,“.”表示这个格子可以放东西,“#”则表示这个格子不能放东西。现在有一条 1∗2 大小的木棒,给定q个子矩阵,求对于给定的每个子矩阵,有多少种放木棒的方案。
q≤105,
1
≤
n
,
m
≤
500
1≤n,m≤500
1≤n,m≤500
解析
考场上我能切的题怕都是水题
实际上我一开始的思路是差分,直到我打了半个小时,统计出了每一个(1,1,x,y)矩阵的答案,发现这东西不能差分……
然后冷静下来一想:emm?这前缀和就完了啊?
具体来讲,我们用四个数组 b [ i ] [ j ] , c [ i ] [ j ] , s u m b [ i ] [ j ] , s u m c [ i ] [ j ] b[i][j],c[i][j],sumb[i][j],sumc[i][j] b[i][j],c[i][j],sumb[i][j],sumc[i][j]’
由于摆放的方式只有横着和竖着,所以:
b [ i ] [ j ] b[i][j] b[i][j]表示第 i i i行的前 j j j个格子横着放的方案数
c [ i ] [ j ] c[i][j] c[i][j]表示第 j j j列的前 i i i个格子竖着放的方案数
s u m b [ i ] [ j ] sumb[i][j] sumb[i][j]表示在矩阵 ( 1 , 1 , i , j ) (1,1,i,j) (1,1,i,j)中横着放的方案数
s u m c [ i ] [ j ] sumc[i][j] sumc[i][j]表示在矩阵 ( 1 , 1 , i , j ) (1,1,i,j) (1,1,i,j)中竖着放的方案数
考虑能不能循环利用一下,发现可以,所以可以节约空间
不过代码里还是开了四个,实际上把sumb改成b,sumc改成c一样可以
然后对于每个询问 ( x 1 , y 1 , x 2 , y 2 ) (x1,y1,x2,y2) (x1,y1,x2,y2)
a
n
s
=
ans=
ans=
(
s
u
m
b
[
x
2
]
[
y
2
]
+
s
u
m
c
[
x
2
]
[
x
2
]
)
(sumb[x2][y2]+sumc[x2][x2])
(sumb[x2][y2]+sumc[x2][x2])
−
(
s
u
m
b
[
x
2
]
[
y
1
]
+
s
u
m
c
[
x
2
]
[
y
1
−
1
]
)
-(sumb[x2][y1]+sumc[x2][y1-1])
−(sumb[x2][y1]+sumc[x2][y1−1])
−
(
s
u
m
b
[
x
1
−
1
]
[
y
2
]
+
s
u
m
c
[
x
1
]
[
y
2
]
)
-(sumb[x1-1][y2]+sumc[x1][y2])
−(sumb[x1−1][y2]+sumc[x1][y2])
+
(
s
u
m
b
[
x
1
−
1
]
[
y
1
]
+
s
u
m
c
[
x
1
]
[
y
1
−
1
]
)
+(sumb[x1-1][y1]+sumc[x1][y1-1])
+(sumb[x1−1][y1]+sumc[x1][y1−1])
结果最后还是归结到容斥上来了~~
上代码:
#include<bits/stdc++.h>
#define rint register int
#define ivoid inline void
#define iint inline int
#define endll '\n'
#define ll long long
using namespace std;
const int N=1e6+5;
const int M=505;
const int inf=0x3f3f3f3f;
int n,m,u,v,w,x,y,z;
char a[M][M];
int b[M][M],c[M][M],sum,tot,res,l,r,mx,my,num;
iint rad()
{
int x=0,f=1;char c;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
int main()
{
// freopen("matrix.in","r",stdin);
// freopen("matrix.out","w",stdout);
n=rad();m=rad();
for(rint i=1;i<=n;i++)scanf("%s",a[i]+1);
//b 横向 c 竖向
for(rint i=1;i<=n;i++){
for(rint j=1;j<=m;j++){
b[i][j]=b[i][j-1];
c[i][j]=c[i-1][j];
if(a[i][j]=='.'&&a[i][j-1]=='.')b[i][j]++;
if(a[i][j]=='.'&&a[i-1][j]=='.')c[i][j]++;
}
}
for(rint i=1;i<=n;i++){
for(rint j=1;j<=m;j++){
b[i][j]=b[i-1][j]+b[i][j];
c[i][j]=c[i][j-1]+c[i][j];
}
}
int T=rad(),x1,y1,x2,y2;
for(rint i=1;i<=T;i++){
x1=rad();y1=rad();x2=rad();y2=rad();
sum=0;
sum+=sumb[x2][y2]+sumc[x2][y2];
sum-=sumb[x2][y1]+sumc[x2][y1-1];
sum-=sumb[x1-1][y2]+sumc[x1][y2];
sum+=sumb[x1-1][y1]+sumc[x1][y1-1];
cout<<sum<<endll;
}
fclose(stdin);
fclose(stdout);
}