题目链接:http://codeforces.com/problemset/problem/611/C
C:
一个矩阵(500*500),有些障碍点和空格点。
现在可以放一种1*2的骨牌,骨牌只能放在空格点。
问对于(x1,y1,x2,y2)这个矩阵,有多少种合法的放骨牌的方式。
很明显的dp[x2][y2] + dp[x1][y1] - dp[x2][y1] - dp[x1][y2]的模式,因为骨牌横竖放置的不一样所以稍微调一下下标就可以。
一.
刚开始想的时候想一下子把二维的答案直接存下来,但显然这样子是没法递推的,所以只能横着算一遍纵着算一遍,不过就是这样相比一维的话,记录的是以i,j为右下角的横或纵的数量,也就是说表示的是一个矩形的,而一维的话表示的是一行或者一列的,所以说只需要在处理的时候,把横或者纵的那条边去掉就可以了,不要多减就可以了!!!
二.用一维前缀和优化的时候,居然卡在了一个坑上,即sum[x2]-sum[x1],而不是x1-1,太坑了,这bug很是不好找啊!!!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e2+10;
char a[maxn][maxn];
int n,m;
int sumrow[maxn][maxn],sumcol[maxn][maxn];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='.'&&a[i][j-1]=='.'){
sumrow[i][j]=sumrow[i][j-1]+1;
}
else sumrow[i][j]=sumrow[i][j-1];
}
}
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
if(a[i][j]=='.'&&a[i-1][j]=='.'){
sumcol[i][j]=sumcol[i-1][j]+1;
}
else sumcol[i][j]=sumcol[i-1][j];
}
}
int q,x1,y1,x2,y2;scanf("%d",&q);
while(q--){
int sum=0;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=x1;i<=x2;i++){
sum+=sumrow[i][y2]-sumrow[i][y1];
}
for(int i=y1;i<=y2;i++){
sum+=sumcol[x2][i]-sumcol[x1][i];
}
printf("%d\n",sum);
}
return 0;
}
二维的代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e2+10;
char a[maxn][maxn];
int n,m;
int sumrow[maxn][maxn],sumcol[maxn][maxn];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
sumrow[i][j]=sumrow[i][j-1]+sumrow[i-1][j]-sumrow[i-1][j-1];
sumcol[i][j]=sumcol[i][j-1]+sumcol[i-1][j]-sumcol[i-1][j-1];
if(a[i][j]=='.'&&a[i][j-1]=='.') sumrow[i][j]++;
if(a[i][j]=='.'&&a[i-1][j]=='.') sumcol[i][j]++;
}
}
int q,x1,y1,x2,y2;scanf("%d",&q);
while(q--){
int sum=0;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
sum+=sumrow[x2][y2]-sumrow[x1-1][y2]-sumrow[x2][y1]+sumrow[x1-1][y1];
sum+=sumcol[x2][y2]-sumcol[x1][y2]-sumcol[x2][y1-1]+sumcol[x1][y1-1];
printf("%d\n",sum);
}
return 0;
}