【GMOJ6826】隔膜
题目
题目链接:https://gmoj.net/senior/#main/show/6826

思路
如果无法找到任意一个 \(k\times k\) 的正方形,显然后手胜。
如果所有 \(k\times k\) 的正方形的交不为空集,那么先手将交集中任意一个点点掉就胜利,所以先手胜。
否则必然存在至少两个不互相相交的正方形,考虑到当只剩下最后两个不互交的正方形时,先手必败,所以假设除了这两个正方形外一共有 \(cnt\) 个格子,两人轮流选一个改变,如果 \(cnt\) 是奇数则先手胜,否则后手胜。
又因为总共的空格子数量等于 \(2k^2+cnt\),与 \(cnt\) 奇偶性相同,所以可以直接判断总共空格子数量。
至于如何判断是否有至少两个正方形不交,直接将所有正方形找出来,分别按照横坐标和纵坐标排序两次,拿横坐标来说,如果排序后第一个正方形上底的横坐标比最后一个正方形下底的横坐标小,那么显然这两个正方形不交。
时间复杂度 \(O(n^2\log n^2)\)。完全可以做到 \(O(n^2)\) 但是懒。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m,sum,cnt,a[N][N],b[N][N];
struct node
{
int a,b,c,d;
}c[N*N];
bool cmp1(node x,node y)
{
return x.a<y.a;
}
bool cmp2(node x,node y)
{
return x.b<y.b;
}
int main()
{
freopen("lcyrcx.in","r",stdin);
freopen("lcyrcx.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%1d",&a[i][j]);
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
if (!a[i][j]) sum++;
}
for (int i=m;i<=n;i++)
for (int j=m;j<=n;j++)
if (b[i][j]-b[i-m][j]-b[i][j-m]+b[i-m][j-m]==0)
c[++cnt]=(node){i-m+1,j-m+1,i,j};
if (!cnt) return printf("yc"),0;
sort(c+1,c+1+cnt,cmp1);
if (c[1].c<c[cnt].a)
return (sum&1) ? printf("rx"),0 : printf("yc"),0;
sort(c+1,c+1+cnt,cmp2);
if (c[1].d<c[cnt].b)
return (sum&1) ? printf("rx"),0 : printf("yc"),0;
printf("rx");
return 0;
}

浙公网安备 33010602011771号