UVA11261 Bishops

给出一个n*n的棋盘和m个象,每个象能够覆盖它所在的对角线,问没有被覆盖的点有多少个

对于一头大象它可以覆盖它所在的从对角线和主对角线,但是些对角线可能相互交叉,因此不能直接求对角线上面的点的个数。n*n的暴力方法很好想出来,但是肯定超时。

我们可以把主对角线和从对角线保存下来,预处理好没有被覆盖的点,dp[i]表示第i条从对角线上面没有被覆盖的点,一共有2*n-1条从对角线。对于从对角线的上半部分,dp[i]初始化为dp[i-2]因为他们的奇偶性相同,则除去第i条从对角线的两个端点以外,如果第i-2条从对角线上的某个点被一条主对角线覆盖,那么它右下角对应的从对角线上的点也被覆盖。时间复杂度为O(N)。


#include<cstdio>
#include<cstring>
#define MAXN 80005
using namespace std;
bool cover_positive[MAXN];//主对角线是否被覆盖
bool cover_negative[MAXN];//从对角线是否被覆盖
int dp[MAXN];//保存第i条从对角线有多少个点没有被覆盖
int n,m;
int main()
{
	int T;
	scanf("%d",&T);
	int cnt = 0;
	while(T--)
	{
		memset(cover_positive,0,sizeof cover_positive);
		memset(cover_negative,0,sizeof cover_negative);
		memset(dp,0,sizeof dp);
		scanf("%d%d",&n,&m);
		int x,y;
		for(int i = 1; i <= m; i++)
		{
			scanf("%d%d",&x,&y);
			cover_positive[n+x-y] = 1;
			cover_negative[x+y-1] = 1;
		}
		
		if(!cover_positive[n]) dp[2*n-1] = dp[1] = 1;//第n条主对角线没有被覆盖,因此第1和第2n-1条对角线上面有一个没有被覆盖的点
		for(int i = 2; i <= n; i++)
		{
			dp[i] = dp[i-2];//dp[i]由dp[i-2]转移过来,第i条对角线比第i-2条对角线多左下和右上2个点,
			//如果第i-2条对角线的其他点被覆盖,那么第i条对角线上的点也会被覆盖
			int num = n - i + 1;
			if(!cover_positive[num]) ++dp[i];
			if(!cover_positive[2*n-num]) ++dp[i];
		}
		for(int i = 2*n-2; i >= n+1; i--)
		{
			dp[i] = dp[i+2];//另外一半对角线与之前的一半相反
			int num = i - n + 1;
			if(!cover_positive[num]) ++dp[i];
			if(!cover_positive[2*n-num]) ++dp[i];
		}
		
		int ans = 0;
		for(int i = 1; i < 2*n; i++)
			if(!cover_negative[i])
				ans += dp[i];
		printf("Case #%d: %d\n",++cnt,ans);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值