codeforces 611C New Year and Domino 容斥定理 动态规划

题目链接 http://codeforces.com/problemset/problem/611/C

题意:
给定一个矩阵(r*c) ,并且矩阵上有障碍物。r<=500,c<=500

q次询问(q<=1,000,000)

每次询问从(r1,c1)到(r2,c2)上,摆放一个1*2的小长方形,不能放到障碍物上,有多少种摆法。

这道题的关键是找到状态转移方程。

我们如果设dp[i][j]为从(1,1)到(i,j)上的摆法数。

那么利用容斥定理。 dp[i][j] =  dp[i][j-1] + dp[i-1][j] -dp[i-1][j-1] + c

其中c为[0,2]的一个数。根据状态转移方程。还要加上如果这个点和左边这个点可放,那么加1,如果这个点和上面这个点可放,再加1。

最后算出dp数组。

当然还有一个难点。

因为题目是求 从(r1,c1)到(r2,c2)上的摆法数,而不是(1,1)到 (r2,c2)的。

最后 答案应该 dp[r2][c2] - dp[r1-1][c1]-dp[r1][c1-1]+dp[r1-1][c1-1]-tks

其中tks应该为边缘的数被加上的,因为我们算的时候,那边已经是格子了,所以左边缘中来自于左边一格的要消去。

上边缘中来自上边缘的要消去。

最后代码如下

#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long LL;
typedef long long ll; 
const int maxn = 5e2+10;
const int modn = 1e9+7;
const int INF = 0x3f3f3f3f;
char str[maxn][maxn];
ll dp[maxn][maxn];
int lef[maxn][maxn];
int u[maxn][maxn];

void show(int a[],int n){
	for(int i=0;i<n;i++){
		printf("%d ",a[i]);
	}printf("\n");
}
int main(){
//	freopen("C:\\Users\\lenovo\\Desktop\\data.in","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF){
		for(int i=0;i<n;i++){
			scanf("%s",str[i]);
		}
		dp[0][0] = 0;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				
				dp[i][j]= (i<0?0:dp[i-1][j])+(j<0?0:dp[i][j-1])-((i<0||j<0)?0:dp[i-1][j-1]);
				
				if(str[i][j]=='.'){
				
					if(i>=1&&str[i-1][j]=='.'){
						dp[i][j]++;
						u[i][j] = 1;
					}
					if(j>=1&&str[i][j-1]=='.'){
						dp[i][j]++;	
						lef[i][j] = 1;
					}
					
				}
				
				
			}
		}
	
		
		
		int k;
		scanf("%d",&k);
		while(k--){
			int x1,x2,y1,y2;
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			x1--;
			y1--;
			x2--;
			y2--;
			ll ans = dp[x2][y2]-(x1-1>=0?dp[x1-1][y2]:0)-(y1-1>=0?dp[x2][y1-1]:0)+((x1-1>=0&&y1-1>=0)?dp[x1-1][y1-1]:0);

			for(int i=x1;i<=x2;i++){
	
				if(lef[i][y1])ans--;
				
			}

			for(int i=y1;i<=y2;i++){
				
				if(u[x1][i])ans--;
			}
			printf("%I64d\n",ans);
		}
	}
	
	
}

猜你喜欢

转载自blog.csdn.net/qq_25955145/article/details/81303606
今日推荐