给出一个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); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-11 17:00:28