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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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=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);
		}
	}
	
	
}

 

你可能感兴趣的:(codeforces 611C New Year and Domino 容斥定理 动态规划)